vue-pixi-renderer v1.1.0
vue-pixi-renderer
使用vue的结构来渲染pixi页面。
Vue.js
PIXI.js
使用说明
目前有很大不足,极有可能出现各种各样的bug!
目前有较多bug
虚拟Node更改自simple-virtual-dom
。
每次该组件重新渲染时,重新生成Node Tree,然后diff、patch。
动画请在函数中直接控制node,而不是使用Vue传递一个不断变化的属性。(每次重新render都要遍历虚拟Node树,耗时较大);
其余皆为pixi属性,详情见PixiJS API Documentation
安装使用
提醒: 目前有较多bug
npm install -save vue-pixi-renderer
import Vue from 'vue'
import VuePixiRenderer from 'vue-pixi-renderer'
Vue.use(VuePIXIRenderer);
基本介绍
<vroot></vroot>
以它为根部建立虚拟node Tree
<container></container>
一个容器。(除root外的任何元素都可作为容器)
创建一个相对坐标系。
<vtext>Text</vtext>
显示字体
<sprite>{src or id}</sprite>
显示图片
<zone></zone>
创建一个区域
<graphics></graphics>
使用pixi.Graphics创建自定义的绘制,需使用init方法
除<vroot></vroot>
外的所有元素均可使用pixiAPI对应的各项数据
比如 <vtext :x=100 :y=100 :anchor='{x: 0.5, y: 0.5}'>Text</vtext>
pixi元素基本属性
x
- 坐标xy
- 坐标yanchor
- { x: number0-1, y: number0-1 } - 图片锚点相对图片宽高的位置,xy均为0.5时为正中心。坐标x、y对应的点的位置也为锚点的位置。选择中心点位置为锚点位置。scale
- { x: number, y: number } - 放大倍数,sprite的width、height属性与之关联。直接调整width、height也会变化scale。tint
- number - 色调,颜色为hex的实际值,如0x0
vroot
<template>
<vroot
:stage='$stage'
在此传入stage,视为要渲染到的Container
如果没有传入stage,则应提供创建pixi Application的参数,如width,height
具体参数列表 http://pixijs.download/release/docs/PIXI.Application.html
:texture='$texture'
在此传入texture,sprite标签中的id则从此对象里寻找
{id1: Texture} <sprite>id1</sprite>
{id2: [] of Texture} <sprite :time='500'>id2</sprite>
则应表现为500ms一帧的AnimateSprite
如果没有传入参数,则<sprite>./img/logo.png</sprite>视作地址src,将会尝试以该地址加载图片.
(请使用public里的图片路径,或import导入图片路径)
>
</vroot>
</template>
<script>
export default {
created() {
// 不应在data中赋值,避免生成响应式数据
this.$stage = window.app.stage;
this.$texture = myTextureObject
},
};
</script>
container
<container :x=100 :y=100 :anchor='{x: 0.5, y: 0.5}'></container>
vtext
<vtext :style='{fill: '#ffffff', fontSize:'17px'}'></vtext>
具体style属性列表请访问
http://pixijs.download/release/docs/PIXI.TextStyle.html
sprite
sprite如果要填写src,请填写public路径里的位置或使用import导入图片。直接填写相对位置图片可能不能被正常导入。
具体是id还是src,请查看 vroot中texture值是否给出
<sprite>src or id</sprite>
zone
<zone
:width=100
:height=100
:radius=0.2 [0~0.5]的一个值
:fillColor='red'
:fillAlpha=1 [0~1]
:lineWidth=3 strokeLine的宽度
:lineColor='blue'
:lineAlpha=1 [0~1]
:alignment=1 strokeLine相对zone的位置,如果为0.5线宽一半在里面,一半在外面
为1表明全部在外面
>
</zone>
graphics
<graphics
:init='drawLine'
>
</graphics>
<script>
请不要写在methods里,methods里的方法会bind Vue的this
data() {
return {
drawLine() {
this.lineStyle(4, 0xFFFFFF, 1);
this.moveTo(0, 0);
this.lineTo(80, 50);
}
}
}
</script>
更多绘制方法请看 http://pixijs.download/release/docs/PIXI.Graphics.html
class的使用
<vtext class='status'>字体</vtext>
<script>
data() {
return {
class: {
status: {
class: 'font',
style: {
fontSize: '17px',
},
},
font: {
style: {
fill: '#ffffff',
fontFamily: 'sans-serif',
},
}
}
}
}
</script>
class相当于一个包含所要填写属性的对象,class里面的值可以填
正常情况下,属性中的值会覆盖class对应的属性,class中的值也会覆盖掉内层引用class对应的值
fit的使用:自适应大小
- 以某个区域自适应大小
<vtext
class="font"
:fit="{zone:[x, y, width, height], ratio:[minRatio,maxRatio], :type="center"}"
>哈哈哈</vtext>
zone: 为区域的x,y,width,height
type:为在区域的基本位置
Array: dx,dy dx,dy均为0~1中的一个值,表明在区域的位置
String: center, left, right, top, bottom
ratio: 放大的比例
number :锁定放大比例
Array: minRatio, maxRatio 最小放大比例,最大放大比例
- 以parent尺寸,自适应大小
<zone class="color" :width=80 :height=25>
<vtext class="status" fit="parent">
fit="parent": 尝试按照parent的大小resize
:fit="{zone:'parent', ratio:[minRatio,maxRatio], type:'center'}"
一些文字
</vtext>
</zone>
event的使用
<zone
v-for="(enemy, index) in enemys"
:key="enemy.name"
:y="3 + (lineHeight+3)*index"
:$index='index'
:class="['bg', { select: index === select}]"
@pointerdown="clickIndex"
>
</zone>
methods: {
clickIndex(event) {
console.log(`you click ${event.target.$index}`)
this.select = event.target.$index;
},
}
如果使用v-for生成多个结构,如何确定点击了哪一个?
使用
:$index='index'
, 如果仅仅使用@pointertap="clickIndex(i)"
,每次重新刷新,函数都要重新更新,因为传入的是重新生成的一个匿名函数,使用$index
,会直接在pixi属性元素中添加$index
属性(\$确保不会覆盖正常属性),这样在点击事件中,通过event.target.$index
即可访问到index。
具体event列表
http://pixijs.download/release/docs/PIXI.Sprite.html#event:click
左侧events栏
pointer是兼容mouse和touch的
pointerdown 按下
pointerup 松起
pointermove 移动
pointertap 点击
pointerout 移出该元素
function使用及淡入淡出效果的实现
:update 传入的方法 每帧执行一次,每秒60帧
:init 传入的方法 在生成该pixi元素时执行
:start 传入的方法,在pixi元素被加入时执行
:show :hide
- 如果传入方法
- show: 在init之后执行.
- hide: 第一个参数为回调函数,请以第一个参数作为该函数的回调
- 如果传入数字,则表明淡入或淡出时间
以下两种方式效果相同<sprite :show=300 :hide=150>./img/logo.png</sprite>
注意,请不要写在methods里,methods里的方法会bind Vue的this<sprite :show='show' :hide='hide'>./img/logo.png</sprite> data() { return { show() { this.changeTo({ alpha: 0, }, { alpha: 1, }, 300); }, hide(cb) { this.changeTo({ alpha: 0, }, 150, cb); } } }
- 如果传入方法
<sprite class="icon" :update="rotate">./img/logo</sprite>
<script>
data() {
return {
rotate() {
this.angle += 1;
},
}
}
</script>
function 中可使用的一些函数
this.loop(from, to, time, repeat = Infinity)
<sprite
:class="logo"
:x=208 :y=208
:anchor='{x: 0.5,y:0.5}'
:init='loop'
>./img/logo.png</sprite>
<script>
data() {
return {
loop() {
this.loop({
alpha: 0,
}, {
alpha: 1,
}, 1000);
},
}
}
</script>
效果为透明度一直改变
this.changeTo()
参数为2 个 为 to,time
参数为3个 to,rime, callback
from,to, callback
参数为4个 from,to。time,callback
this.tween();
/* 不填参数默认为以自己建立一个tween,填参数则以参数对象
具体使用方法见https://github.com/tweenjs/tween.js/blob/master/docs/user_guide.md */
this.tween().to({alpha: 1}, 1000).start();
简单实例
<template>
<vroot class='app' :width='width' :height='height'>
<zone
:x=20
:y=180
:width=100
:height=100
:radius=0.3
:fillAlpha=0.3
:lineWidth=5
lineColor="blue"
:lineAlpha=0.3
@pointertap='clickMe'
>
<vtext class='text' fit='parent'>{{ button }}</vtext>
</zone>
<vtext class='text' :start='show'>{{ str }}</vtext>
<sprite class="logo" :update='rotate' :start='loop'>{{ logo }}</sprite>
</vroot>
</template>
<script>
import logo from './assets/logo.png'
export default {
name: 'App',
data() {
const width = 300;
const height = 300;
return {
logo,
width,
height,
str: 'vue-pixi-renderer',
button: 'Click Me!',
class: {
logo: {
x: width / 2,
y: height / 2,
anchor: {
x: 0.5,
y: 0.5,
}
},
text: {
style: {
fontSize: '22px',
fill: 'red',
fontFamily: 'sans-serif',
}
},
},
show() {
this.changeTo({
x: 300,
y: 300,
},{
x: 0,
y: 0,
}, 1000);
},
rotate() {
this.angle += 1;
},
loop() {
this.changeTo({
x: 0,
}, {
x: width / 2,
}, 1000);
this.loop({
alpha: 0,
}, {
alpha: 1,
}, 1000);
},
}
},
methods: {
clickVue() {
this.str = 'you click Vue';
},
clickMe() {
this.button = 'you click me QAQ';
setTimeout(() => {
this.button = 'Click Me!'
}, 1000);
}
}
}
</script>
示例网站
工程相关
index.js - vue插件的导出
|— components :vue基本组件,functional组件,和 虚拟Tree的实例
—— vroot 为基本组件,附带一个Tree的实例
—— 其余组件均为functional 组件
|——lib
——diff.js - 虚拟node树的diff
——extend.js - 为避免热重载Ticker一直增加导致动画变快而分离开
——index.js - 整体模块的导出
——node.js - 虚拟Node的创建及渲染 以及从functional的参数h,context中创建node的方法
——nodes.js - pixi.js基本元素的包装,增加的一些方法
—— patch.js - 虚拟node树的patch
—— Render.js - 又一层包装,对一些参数的处理成nodes.js对应元素的参数,渲染Node由此处 —— texture.js - sprite中默认系统Sprite:Loading,error和 加载图片后更新node的方法
—— utils.js - 一些utils函数,比如颜色,deep assign, clone
目前BUG:
- 由于没有显式指定Key,在结构发生变化时,比如中间有几个元素消失时,diff判断不是直接移除中间部分,而是逐个比对,导致后续元素使用replace而增大工作量。Vue的functional没有this,暂时没有找到给每一个元素一个单独id作为key的方案。
- fit指定为'parent'时,内部元素改变时可能不能正常更新,父级元素改变时同样可能不能正常更新。
- Graphics重新绘制后可能width,height不重新改变,导致fit更新失败。
- 元素的复用有没有可能?清空一个元素再把值赋予?
TODO:
- 性能感觉不好。如果每帧渲染一次感觉是极大的负担,不建议更改属性完成某些动画操作。如何性能优化?不确定哪些属性更改了,要全盘比对,耗资源较大。感觉主要适用于一些ui的绘制。
- 提供:texture参数时 sprite的显示和报错未测试
更新日志:
4-5:
- 默认将所有node的interactiveChildren设为false,当一个node有事件时,向上将parent的interactiveChildren设置为true
- 修复了v-if使用中不能正常diff的问题。
- 完善了图片路径加载的报错提示、热重载、以及用系统警告图片代替加载失败的图片等。
- 增加了异步删除逻辑,可以在一个元素remove时,传入:remove函数实现消失动画。
4-7:
- 增加了 show,hide方法,用hide来代替:remove
- 修复了sprite加载热重载的bug