【開源】微信小程序、小游戲以及 Web 通用 Canvas 渲染引擎
小程序、小游戲以及 Web 通用 Canvas 渲染引擎
到 GitHub 下載 cax 自定義組件,然后小程序引入 cax 自定義組件:
└── cax
├── cax.js
├── cax.json
├── cax.wxml
├── cax.wxss
└── index.js
在 page 或者 component 里聲明依賴:
{
"usingComponents": {
"cax":"../cax/cax"
}
}
在的 wxml 里引入 cax 標(biāo)簽:
<cax id="myCanvas"></cax>
在 js 里渲染邏輯:
import cax from '../cax/index'
Page({
onLoad: function () {
//比 web 里使用 cax 多傳遞 this,this 代表 Page 或 Component 的實(shí)例
const stage = new cax.Stage(200, 200, 'myCanvas', this)
const rect = new cax.Rect(100, 100, {
fillStyle: 'black'
})
rect.originX = 50
rect.originY = 50
rect.x = 100
rect.y = 100
rect.rotation = 30
rect.on('tap', () => {
console.log('tap')
})
stage.add(rect)
stage.update()
}
})
效果如下所示:
除了 tap 事件,也可以幫 rect 綁定其他觸摸事件:
rect.on('touchstart', () => {
console.log('touchstart')
})
rect.on('touchmove', () => {
console.log('touchmove')
})
rect.on('touchend', () => {
console.log('touchend')
})
到 GitHub 下載 cax 小游戲示例,目錄結(jié)構(gòu)如下:
const stage = new cax.Stage()
和小程序以及 Web 不同的是,小游戲創(chuàng)建 Stage 不需要傳任何參數(shù)。
通過 npm 或者 CDN 獲取:
npm i cax
import cax from 'cax'
const stage = new cax.Stage(200, 200, '#renderTo')
const rect = new cax.Rect(100, 100, {
fillStyle: 'black'
})
stage.add(rect)
stage.update()
除了 Stage 構(gòu)造函數(shù)比小程序第四個(gè)參數(shù) this,其他使用方式都一樣。
用于分組, group 也可以嵌套 group,父容器的屬性會(huì)疊加在子屬性上, 比如:
const group = new cax.Group()
const rect = new cax.Rect(100, 100 {
fillStyle: 'black'
})
group.add(rect)
stage.add(group)
stage.update()
group 擁有常用的 add 和 remove 方法進(jìn)行元素的增加和刪除。先 add 的會(huì)先繪制,所有后 add 的會(huì)蓋在先 add 的上面。
const bitmap = new cax.Bitmap(img)
stage.add(bitmap)
stage.update()
如果只傳 url 而不是 Image 對(duì)象的實(shí)例,需要這樣:
const bitmap = new cax.Bitmap('./wepay.png', ()=>{
stage.update()
})
stage.add(bitmap)
這里需要注意小程序需要配置 downloadFile 需要配置合法域名才能正常加載到圖片。
可以設(shè)置圖片裁剪顯示區(qū)域,和其他 transform 屬性:
bitmap.rect = [0, 0, 170, 140]
bitmap.x = 200
序列幀動(dòng)畫組件,可以把任意圖片的任意區(qū)域組合成一串動(dòng)畫。
const sprite = new cax.Sprite({
framerate: 7,
imgs: ['./mario-sheet.png'],
frames: [
// x, y, width, height, originX, originY ,imageIndex
[0, 0, 32, 32],
[32 * 1, 0, 32, 32],
[32 * 2, 0, 32, 32],
[32 * 3, 0, 32, 32],
[32 * 4, 0, 32, 32],
[32 * 5, 0, 32, 32],
[32 * 6, 0, 32, 32],
[32 * 7, 0, 32, 32],
[32 * 8, 0, 32, 32],
[32 * 9, 0, 32, 32],
[32 * 10, 0, 32, 32],
[32 * 11, 0, 32, 32],
[32 * 12, 0, 32, 32],
[32 * 13, 0, 32, 32],
[32 * 14, 0, 32, 32]
],
animations: {
walk: {
frames: [0, 1]
},
happy: {
frames: [5, 6, 7, 8, 9]
},
win: {
frames: [12]
}
},
playOnce: false,
currentAnimation: "walk",
animationEnd: function () {
}
});
文本對(duì)象
const text = new cax.Text('Hello World', {
font: '20px Arial',
color: '#ff7700',
baseline: 'top'
})
繪圖對(duì)象,用于使用基本的連綴方式的 Canvas 指令繪制圖形。
const graphics = new cax.Graphics()
graphics
.beginPath()
.arc(0, 0, 10, 0, Math.PI * 2)
.closePath()
.fillStyle('#f4862c')
.fill()
.strokeStyle('black')
.stroke()
graphics.x = 100
graphics.y = 200
stage.add(graphics)
與 Graphics 不同的是, Shape 一般擁有有限的寬高,所以可以使用離屏 Canvas 進(jìn)行緩存。下面這些屬于 Shape。
const rect = new cax.Rect(200, 100, {
fillStyle: 'black'
})
const circel = new cax.Circel(10)
const ellipse = new cax.Ellipse(10)
注意:從技術(shù)上小游戲和 Web 可以離屏 Canvas,小程序不行,因?yàn)樾〕绦虿恢С謩?dòng)態(tài)創(chuàng)建離屏 Canvas。
Element 是多種元素的組合,如 Bitmap、Group、 Text、 Shape 等混合起來的圖像。
const button = new cax.Button({
width: 100,
height: 40,
text: "Click Me!"
})
屬性名 | 描述 |
---|---|
x | 水平偏移 |
y | 豎直偏移 |
scaleX | 水平縮放 |
scaleY | 豎直縮放 |
rotation | 旋轉(zhuǎn) |
skewX | 歪斜 X |
skewY | 歪斜 Y |
originX | 旋轉(zhuǎn)基點(diǎn) X |
originY | 旋轉(zhuǎn)基點(diǎn) Y |
屬性名 | 描述 |
---|---|
alpha | 元素的透明度 |
注意這里父子都設(shè)置了 alpha 會(huì)進(jìn)行乘法疊加。
屬性名 | 描述 |
---|---|
compositeOperation | 源圖像繪制到目標(biāo)圖像上的疊加模式 |
注意這里如果自身沒有定義 compositeOperation 會(huì)進(jìn)行向上查找,找到最近的定義了 compositeOperation 的父容器作為自己的 compositeOperation。
屬性名 | 描述 |
---|---|
cursor | 鼠標(biāo)移上去的形狀 |
事件名 | 描述 |
---|---|
tap | 手指觸摸后馬上離開 |
touchstart | 手指觸摸動(dòng)作開始 |
touchmove | 手指觸摸后移動(dòng) |
touchend | 手指觸摸動(dòng)作結(jié)束 |
drag | 拖拽 |
事件名 | 描述 |
---|---|
click | 元素上發(fā)生點(diǎn)擊時(shí)觸發(fā) |
mousedown | 當(dāng)元素上按下鼠標(biāo)按鈕時(shí)觸發(fā) |
mousemove | 當(dāng)鼠標(biāo)指針移動(dòng)到元素上時(shí)觸發(fā) |
mouseup | 當(dāng)在元素上釋放鼠標(biāo)按鈕時(shí)觸發(fā) |
mouseover | 當(dāng)鼠標(biāo)指針移動(dòng)到元素上時(shí)觸發(fā) |
mouseout | 當(dāng)鼠標(biāo)指針移出元素時(shí)觸發(fā) |
tap | 手指觸摸后馬上離開 |
touchstart | 手指觸摸動(dòng)作開始 |
touchmove | 手指觸摸后移動(dòng) |
touchend | 手指觸摸動(dòng)作結(jié)束 |
drag | 拖拽 |
自定義 Shape 繼承自 cax.Shape:
class Sector extends cax.Shape {
constructor (r, from, to, option) {
super()
this.option = option || {}
this.r = r
this.from = from
this.to = to
}
draw () {
this.beginPath()
.moveTo(0, 0)
.arc(0, 0, this.r, this.from, this.to)
.closePath()
.fillStyle(this.option.fillStyle)
.fill()
.strokeStyle(this.option.strokeStyle)
.lineWidth(this.option.lineWidth)
.stroke()
}
}
使用 Shape:
const sector = new Sector(10, 0, Math.PI/6, {
fillStyle: 'red'
lineWidth: 2
})
stage.add(sector)
stage.update()
自定義 Element 繼承自 cax.Group:
class Button extends cax.Group {
constructor (option) {
super()
this.width = option.width
this.roundedRect = new cax.RoundedRect(option.width, option.height, option.r)
this.text = new cax.Text(option.text, {
font: option.font,
color: option.color
})
this.text.x = option.width / 2 - this.text.getWidth() / 2 * this.text.scaleX
this.text.y = option.height / 2 - 10 + 5 * this.text.scaleY
this.add(this.roundedRect, this.text)
}
}
export default Button
使用:
const button = new cax.Button({
width: 100,
height: 40,
text: "Click Me!"
})
一般情況下,稍微復(fù)雜組合體都建議使用繼承自 Group,這樣利于擴(kuò)展也方便管理自身內(nèi)部的元件??梢钥吹叫∮螒虻?DEMO 里的 Player、Bullet、Enemy、Background 全都是繼承自 Group。
MIT