vue-pixi-renderer

1.1.0 • Public • Published

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);

基本介绍

  1. <vroot></vroot>

以它为根部建立虚拟node Tree

  1. <container></container>

一个容器。(除root外的任何元素都可作为容器)

创建一个相对坐标系。

  1. <vtext>Text</vtext>

显示字体

  1. <sprite>{src or id}</sprite>

显示图片

  1. <zone></zone>

创建一个区域

  1. <graphics></graphics>

使用pixi.Graphics创建自定义的绘制,需使用init方法

<vroot></vroot> 外的所有元素均可使用pixiAPI对应的各项数据

​ 比如 <vtext :x=100 :y=100 :anchor='{x: 0.5, y: 0.5}'>Text</vtext>

pixi元素基本属性

  • x - 坐标x
  • y - 坐标y
  • anchor - { x: number[0-1], y: number[0-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的使用:自适应大小

  1. 以某个区域自适应大小
<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] 最小放大比例,最大放大比例

  1. 以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>
    <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);
        }
      }
    }

注意,请不要写在methods里,methods里的方法会bind Vue的this

<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

Package Sidebar

Install

npm i vue-pixi-renderer

Weekly Downloads

5

Version

1.1.0

License

MIT

Unpacked Size

192 kB

Total Files

32

Last publish

Collaborators

  • voderl