如何优雅的使用微信小程序Canvas画布

简介

MinAs 是一个运行在微信小程序的JavaScript 库,仅仅13kb左右,旨在让开发者能像使用 pixijs和Flash AS3 一样,在微信小程序的 Canvas 中优雅地使用精灵Sprite、补简动画Tween、逐帧动画精灵AnimatedSprite。同样也特别适合那些想在微信小程序中开发小游戏功能的项目,又或者你想做个游戏界面风格的应用小程序。

后续作者会推出使用这个库开发的简单的小游戏示例、ui库等。

git地址:https://gitee.com/wugemianfei/min-as

npm地址:https://www.npmjs.com/package/min-as

功能特性

仅仅 10 几 kb 左右,和那些动则几百 kb 的库相比,太适合寸土寸金的小程序了。

支持创建普通精灵(`Sprite`)和动画精灵(`AnimatedSprite`)。

提供资源加载器,方便加载图片和动画资源。

支持精灵的变换动画和事件处理。

支持简单的 Tween 补间动画。

安装与导入

小程序中使用

直接复制 min-as.umd.js 文件到小程序的文件夹中比如 utils 中,然后在微信小程序的 *.js 文件中引入。

import MinAs, { Sprite, AnimatedSprite } from './utils/min-as.umd.js'

uniapp 中使用

npm install min-as

import MinAs, { Sprite, AnimatedSprite } from 'min-as'

开始使用

uniapp 中使用

uniapp 完整代码,需要注意 canvas 的调用方式,demo 是 vue2 的写法,vue3 写法差不多。

<template>

  <view class="content">

    <canvas type="2d" id="myCanvas" class="gamecont" :disable-scroll="true" @touchstart="touchEvent"

      @touchmove="touchEvent" @touchend="touchEvent" @touchcancel="touchEvent"></canvas>

  </view>

</template>

<script>

import MinAs, { Sprite, AnimatedSprite } from "min-as"

let minAs = null

export default {

  data() {

    return {

      title: 'Hello'

    }

  },

  mounted() {

    const info = uni.getSystemInfoSync()

    const sw = info.screenWidth //获取屏幕宽高

    const sh = info.windowHeight //获取屏幕宽高

    const ratio = info.devicePixelRatio

    //#ifdef MP-WEIXIN

    wx.createSelectorQuery()

      .select('#myCanvas')

      .node(({ node: canvas }) => {

        //新版 canvas 只能这么获取

        const ctx = canvas.getContext('2d')

        canvas.width = sw * ratio

        canvas.height = sh * ratio

        ctx.scale(ratio, ratio)

        //初始化 minAs 实例 

        minAs = new MinAs()

        minAs.init({ canvas })

        //

        const sprite = new Sprite({

          x: 10,

          y: 10,

          width: 375,

          height: 100,

          backgroundColor: "#f20"

        })

        minAs.appendChild(sprite)

        //开始渲染

        minAs.render()

      }).exec();

    //#endif

  },

  methods: {

    //#ifdef MP-WEIXIN

    touchEvent(e) {

      //小程序事件绑定至 minAs 实例

      if (minAs) {

        minAs.dispatchEvent(e)

      }

    }

    //#endif

  }

}

</script>

<style lang="scss" scoped>

.content {

  width: 100vw;

  height: 100vh;

  .gamecont {

    position: absolute;

    left: 0;

    top: 0;

    width: 100%;

    height: 100%;

    z-index: 0;

  }

}

</style>

原生微信小程序中使用

微信 *.wxml 部分片段。

<canvas type="2d" id="myCanvas" bind:touchstart="touchEvent"

      bind:touchmove="touchEvent" bind:touchend="touchEvent" bind:touchcancel="touchEvent"></canvas>

微信 *.js 部分片段。

import MinAs, { Sprite, AnimatedSprite } from 'min-as'

onReady() {

  const query = wx.createSelectorQuery()

  query.select('#myCanvas')

    .fields({ node: true, size: true })

    .exec((res) => {

      const minAs = new MinAs()

      const canvas = res[0].node

      const ctx = canvas.getContext('2d')

      const dpr = wx.getSystemInfoSync().pixelRatio

      canvas.width = res[0].width * dpr

      canvas.height = res[0].height * dpr

      ctx.scale(dpr, dpr)

      //开始初始化 minAs

      minAs.init({ canvas })

      //定义红色精灵

      const sprite = new Sprite({ x: 100, y: 100, width: 100, height: 100, backgroundColor: 'red' })

      //监听事件,如果无效请检查是否绑定了 touchEvent 事件

      sprite.on("touchstart", (e) => {

        console.log("红色精灵被点击:", e)

      }

      minAs.appendChild(sprite)

      minAs.render()

      //初始化结束

    })

},

touchEvent(e) {

  //非常重要,将微信小程序事件传递给 minAs

  if (this.minAs) {

    this.minAs.dispatchEvent(e)

  }

}

补间动画

MinAs 支持使用 Tween 进行补间动画。以下是如何创建和使用 Tween 的示例 js 片段:

// 假设我们有一个精灵对象 sprite, 需要将它移动到 (300, 300) 位置, 并在 2 秒内完成, 运动曲线减速"Out"

const sprite = new Sprite({ x: 0, y: 0, width: 100, height: 100, backgroundColor: 'red' })

const tween = minAs.transition(sprite,  {

  x: 300,

  y: 300,

  duration: 2,

  timing:"Out"

  onEnd: () => {

    console.log("动画结束")

  }

})

// 假设我们有一个精灵对象 sprite, 需要将它移动到 (300, 300) 位置, 然后再运行到(400, 400)位置,一直往复运动"

const sprite = new Sprite({ x: 0, y: 0, width: 100, height: 100, backgroundColor:'green' })

const tweenCtr = minAs.transitionList(sprite,  [

  { x: 300, y: 300, duration: 2, timing:"Out" },

  { x: 400, y: 400, duration: 2, timing:"Out" }

], {

  loop: true,

  onEnd: () => {

    console.log("动画结束")

  }

})

MinAs 只是封装简单的匀速、加速、减速、先加速再减速。如果需要更高级更精细的运动,推荐直接使用 tween.js 库进行操作。

逐帧动画

MinAs 支持逐帧动画,允许开发者创建逐帧动画精灵。以下是如何创建和使用逐帧动画的示例:

const urls = {

  laoshu: "https://**********demodata/laoshu.json",

}

//如果想修改 json 默认图片地址,还可以自定义贴图地址

//  const urls = {

//    laoshu2: {

//      url: "https://**********demodata/laoshu.json",

//      metaImage: "https://*********/**.png"

//    }

//  }

minAs.assetsLoad(urls).then(keys=> {

        const anSprite = new AnimatedSprite({

          x: 400,

          y: 200,

          width: 48,

          height: 48,

          backgroundColor: "#f20",

          currentFrame: 3,

          json: minAs.getAssets('laoshu')

        })

        minAs.appendChild(anSprite)

        //运行动画

        //anSprite.play()

})

制作逐帧动画过程

直接下载免费制作 工具 ShoeBox,当然其他工具也行

按照 doc 文件夹中的 3 张图片操作,即可得到最后要的 json 文件和纹理贴图。

API 说明

`MinAs` 类

`init(options)`:初始化 MinAs 实例,传入包含 `canvas` 的配置对象。

参数类型描述

optionsObject初始化数据,目前就一个参数{ canvas }。

options.canvaswx.Canvas微信小程序的 Canvas 节点对象。

`use(BasePlugin, options)`:加载自定义插件。

参数类型描述

BasePluginBasePlugin插件实例(详细请看自定义插件部分)

optionsObject| undefined自定义传递给插件数据

`destroy()`: 销毁 MinAs 实例(全局销毁)。

`dispatchEvent(e)`:绑定 wx.Canvas 事件。

参数类型描述

ewx.Event微信小程序的事件对象。

`on(eventName, callback)`:注册事件。

参数类型描述

eventNameString不要使用内置名称: "touchstart", "touchmove", "touchend", "touchcancel"

callbackFunction回调函数,返回事件 e 对象

`off(eventName, callback)`: 移除事件。

参数类型描述

eventNameString不要使用内置名称:"touchstart", "touchmove", "touchend", "touchcancel"

callbackFunction回调函数,返回事件 e 对象

`emit(eventName, ...args)`:触发事件。

参数类型描述

eventNameString不要使用内置名称:"touchstart", "touchmove", "touchend", "touchcancel"

argsany任意数据

`render(callback)`:开始渲染。

参数类型描述

callbackFunction| undefined持续调用

`appendChild(sprite)`:将精灵添加到渲染列表。

参数类型描述

spriteSprite精灵对象

`removeChild(sprite)`:移除子精灵。

参数类型描述

spriteSprite精灵对象

`removeAll()`:移除所有子精灵。

`assetsLoad(urls, progressCallback)`:加载资源。

参数类型描述

`urls`String| Array | Object当为 string 类型时候加载一个,Array 加载多个。(单个数据可以直接使用 string 类型,也可以写成{url: string}这样的 object 结构)

`progressCallback`Function| undefined加载进度,当 urls 为数组时才有意义,返回加载百分比 number。

返回值

返回值类型描述

resPromise回一个 Promise,完成后返回加载的资源键名或者键名列表

`getAssets(key)`:根据键名获取已加载的资源。

参数类型描述

keyString| undefined资源建名称

返回值

返回值类型描述

keyString| Array当 key 为 string 返回当前资源的内容,key 为空或者不存在时候返回全部资源列表

`transition(sprite, options)`:内置 tween 过渡方法。

参数类型描述

spriteSprite精灵实例

optionsObject过渡配置参数

options.durationnumbet\undefind

options.timing"Linear", "In", "Out", "InOut"运动函数名称,默认 Linear

options.onUpdateFunction| undefind运动结束回调,返回运动的 srpite 精灵

options.onEndFunction| undefind运动结束回调,返回 srpite 精灵

options.[..res]anysprite 精灵中需要变化到的任意 number 属性,比如精灵的 x,y,scaleX,scaleY,width,height,angle,opacity

返回值

返回值类型描述

tweenTween返回一个 tween 运动对象

tween.resumeFunction恢复动画

tween.pauseFunction暂停动画

tween.stopFunction停止动画

`transitionList(sprite, optionslist, options)`:内置 tween 过渡方法列表,多个 transition 组成的运动列表。

参数类型描述

spriteSprite精灵实例

optionslistArray多个 transition 配置参数的集合,会按照顺序一个完成再执行下一个,持续下去

options.loopBoolean| undefind是否循环 ,默认 true

options.onUpdateFunction| undefind运动结束回调,返回运动的 srpite 精灵

options.onChangeFunction| undefind运动切换的时候回调,返回运动的 srpite 精灵和下标 index

options.onEndFunction| undefind运动结束回调,返回 srpite 精灵, 当 loop 为 true 才有意义

返回值

返回值类型描述

tweenCtrObject返回一个控制运动的对象

tweenCtr.resumeFunction恢复动画

tweenCtr.pauseFunction暂停动画

tweenCtr.stopFunction停止动画

`Sprite` 类

构造函数接受一个配置对象,支持以下属性:

`x`:精灵的 x 坐标。默认 0

`y`:精灵的 y 坐标。默认 0

`width`:精灵的宽度。默认 0

`height`:精灵的高度。默认 0

`scaleX`:精灵的水平缩放比例。默认 1

`scaleY`:精灵的垂直缩放比例。默认 1

`backgroundColor`:精灵的背景颜色。默认 ""

`texture`:精灵的纹理(图片)。默认 ""

`angle`:精灵的旋转角度。默认 0

`opacity`:精灵的透明度。默认 1

`hotPolygon`:元素的热点多边形, 用于事件碰撞检测。默认最小外接矩形[[0, 0], [width, 0], [width, height], [0, height]]。如果是异形需要精准点击检查,这里可以自己定义热区数组

const sprite = new Sprite({

    x: 0,

    y: 0,

    width: 200,

    height: 200,

    hotPolygon: [

      [100, 0], [138, 72], [200, 72], [146, 116],

      [162, 180], [100, 146], [38, 180], [54, 116], [0, 72], [62, 72]

    ],

    showHotPolygon: true,

    backgroundColor: 'red',

})

`showHotPolygon`:是否显示热区多边形。默认 false,主要用来调试时候看热区位置和大小

`visible`:精灵的可见性。默认 true

`onDraw`:绘制回调函数 Function,返回精灵实例,用于自定义绘制逻辑。默认空

方法:

`on(eventName, callback)`:监听事件。

参数类型描述

eventName"touchstart", "touchmove", "touchend", "touchcancel"监听事件

callbackFunction回调函数,返回事件 e 对象

`appendChild(sprite)`:将精灵添加到渲染列表。

参数类型描述

spriteSprite精灵对象

`removeChild(sprite)`:移除子精灵。

参数类型描述

spriteSprite精灵对象

`removeAll()`:移除所有子精灵。

`removeFromParent()`:将此对象从其当前父对象中移除。

`toFront()`:将精灵层级置顶。

`toBack()`:将精灵层级置底。

`getIndex()`:获取当前精灵层级。

`setIndex(index)`:将精灵层级到指定位置。

`AnimatedSprite` 类

继承自 `Sprite`,构造函数额外支持以下属性:

`currentFrame`:初始帧索引。默认 0

`loop`:是否循环播放。默认 true

`animationSpeed`:帧率 number, 默认 15(帧/秒)

`json`:动画配置 JSON。来自 ShoeBox 导出的帧动画标准 json 文件,详细请看下面帧动画部分。

方法:

`play(frame)`:播放动画,可指定播放帧。

参数类型描述

frameNumber| undefind为空时候从头播放,不为空从指定帧播放

`pause()`:暂停动画。

`stop(frame)`:停止动画,可指定停止帧。

参数类型描述

spriteNumber| undefind为空时停在最后一帧,不为空停在指定帧

自定义插件

MinAs 提供了一个插件机制,允许开发者自定义插件以扩展其功能。以下是如何创建和使用自定义插件的步骤:

你可以直接复制项目中的 plugin 文件夹到你的任意位置,然后引入文件,使用 minAs.use 加载插件

假设我们开发的插件叫 DemoPlugin,我们先定义类然后 extends BasePlugin 继承一下这个基础类,然后就可以使用 minAs 内部的一些方法

如果需要将插件的方法挂在到 minAs 对象上去,只要在 apis 数组中写上方法名称即可

比如你写了个方法叫 demoMethod,你需要 static apis = ["demoMethod"], 然后就可以在外部使用 minAs.demoMethod

//引入插件

import DemoPlugin from './plugin/DemoPlugin.js'

//挂载插件

minAs.use(DemoPlugin, {})

//使用插件方法

minAs.demoMethod()

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容