pixijs 是一个canvas 2D框架
pixi.js创建所有widget 都是有一个完整的object Display Object 他包括元素定位, 宽高,渲染方式等等方法..除了ParticleContaine这些提升性能优化的API,这个一个高性能容器,优化就是省略一些多余的object Display Object .
注:我使用的版本是V6 , 6.4.2。大版本各个API会变动,引入正确版本来开发。网上使用的是V4,略有差别
1、 引入
// 引入pixi.jsyarn add pixi.js
2、一些主要的API:
import {Application, //渲染器,舞台(canvas)Contanier, // 容器Sprite, //精灵 是一个舞台中物体基础(display Object)Loader, // 加载器 一些资源的加载器(比如说:图片、文字之类的)Text, // 文字 (一个特殊的精灵,支持display ObjectTextStyle, //文字样式Texture //纹理, 给精灵加载纹理} from 'pixi.js';
3、创建一个舞台(Canvas)
//创建一个宽度400,高度400 ,背景色为#000的 canvasconst renderer = new Application({width:400,height:400,backgroudColor:0x000000});//将Canvas 放入 Html 中const body = document.body;body.appendChild(renderer);
4、创建一个容器(container)
容器的作用是给一些东西分组,方便管理;比如一个游戏分为:
1、开始界面
2、结束界面
3、游戏画面
三个可以分为三组,便于管理。
# 创建一个舞台(容器)// 一个游戏,或者一个2d的渲染器。如果里面的内容过于复杂或者多。需要一个或者多个容器包裹管理。比如:// 比如,坦克大战,玩家控制的坦克,随机生成的敌方坦克,这里可以创建两个容器用来单独管理const contanier = new Contanier();// 将容器放入舞台(canvas) 中renderer.stage.addChild(contanier);
额外的容器(ParticleContainer)
这个 使用方法跟container 是一样的,是用来做性能优化的。有时候放入在你放入容器的sprite不需要整个display object 树 ,只需要部分关键的display object ,比如x,y,width,height等关键属性。
(粒子效果就是创建很多精灵,放入性能容器里面)
# 创建一个高性能舞台(容器)const prticleCntanier = new ParticleContainer();// 将容器放入舞台(canvas) 中renderer.stage.addChild(prticleCntanier);
额外的api
删除容器内精灵
//删除容器内所有的精灵container.removeChildren();//删除指定下标的精灵contanier.removeChildAt(index);//删除一个或者多个精灵contanier.removeChild(...children)
获取容器中的精灵(child)
可以使用获取容器中的display object属性,然后拿到children,比如
container.children(index)
也可以使用更加优雅的方法, pixijs已经帮我封装好了一些方法
//根据下标拿到容器中的指定精灵,等同于上面的方法container.getChildAt(index);//deep:boolean,name:string 别名 。根据别名找到精灵,是否开启递归搜索,默认false; 比较耗费性能container.getChildByName(name,deep);//根据精灵返回下标container.getChildIndex(child);
将容器添加精灵到指定的下标
//暂时我没用过,贴上官网的注释//Adds a child to the container at a specified index. If the index is out of bounds an error will be throwncontainer.addChildAt(child,index)
5、创建一个精灵
// 创建精灵,并给精灵设置图片let sprite = PIXI.Sprite.from('assets/image.png');//将精灵放入container(容器)或者application(舞台)当中//容器container.addchild(sprite);//高性能容器//prticleCntanier.addchild(sprite);//舞台renderer.stage.addchild(sprite)
使用texture来给精灵增加纹理
//创建一段纹理const texture = PIXI.Texture.from('assets/image.png');//将纹理放入精灵中const sprite = PIXI.Sprite(texture);
通过 loader来高性能加载资源
当资源很多很且复杂的时候,可以通过loader 来加载图片、视频等资源。而当sprite使用loader的资源时候,就不能使用from。
注:通过loader可以写一个资源加载器的游戏开始页面。在刚进入游戏的时候可以写一个In progress 加载页面
//使用 loader 加载器const loader = Loader.shared;loader.add('name', assetsUrl).load(loaded)const loaded = (loader, resources) => {// resources 是资源的加载对象。key是name,value 是 资源// They have a couple default properties:// - `url`: The URL that the resource was loaded from// - `error`: The error that happened when trying to load (if any)// - `data`: The raw data that was loaded// also may contain other properties based on the middleware that runs.sprites.bunny = new PIXI.TilingSprite(resources.bunny.texture);sprites.spaceship = new PIXI.TilingSprite(resources.spaceship.texture);sprites.scoreFont = new PIXI.TilingSprite(resources.scoreFont.texture);}
还能通过雪碧图,和一个确定雪碧图position的json文件来更加优化性能
//异步加载图片,并使用他PIXI.Loader.shared.add("assets/spritesheet.json").load(setup);function setup() {//雪碧图,确定图片位置let sheet = Loader.shared.resources["assets/spritesheet.json"].spritesheet;let sprite = new PIXI.Sprite(sheet.textures["image.png"]);};
loader 加载资源的一些API
// loader加载远程资源的过程或者生命周期loader.onProgress.add(() => {}); // called once per loaded/errored fileloader.onError.add(() => {}); // called once per errored fileloader.onLoad.add(() => {}); // called once per loaded fileloader.onComplete.add(() => {}); // called once when the queued resources all load.
特殊的精灵,平铺精灵(TilingSprite)
在一定范围内,你需要重复一个纹理,使他们创建无线滚动的背景效果。
let tilingSprite = new PIXI.extras.TilingSprite(texture, width, height);
| name | defluat | desc |
|---|---|---|
| texture | 纹理 | |
| width | 100 | 平铺精灵的宽度 |
| height | 100 | 平铺精灵的高度 |
6、创建一段文字并给他样式
//创建文字const mark = new Text('我创建一段文字',new TextStyle({fontFamily: "Arial",fontSize: 36,fill: "white",stroke: "#ff3300",strokeThickness: 4,dropShadow: true,dropShadowColor: "#cccccc",dropShadowBlur: 4,dropShadowAngle: Math.PI / 6,dropShadowDistance: 6,});//将文字放入容器(container)中container.addChild(mark);
当一些精灵(可以是文字,纹理,绘制,哪怕是容器)存入一个容器中时,他会有一个相对位置和绝对位置,相对位置就是widget 在容器中的位置,绝对位置是相对的canvas 左上角的位置。
//使用Graphics创建一段墙壁,放入容器中,因为他drawRect 绘制要确定X,Y 这个X,Y是相对容器位置的//需要使用position.set设置绝对位置才能到canvas的实际位置const leftWall = new Graphics();leftWall.beginFill(0xde3249);leftWall.drawRect(0, 0, 10, this.height as number);leftWall.position.set(0, 0);leftWall.endFill();container.addChild(leftWall);
附录,贴上两端祖传代码(百度也能查到):
一段,键盘事件的函数代码:
interface keyProps {value: stringisDown:booleanisUp:booleanpress?: anyrelease?: anydownHandler:(Event:KeyboardEvent)=>voidupHandler:(Event:KeyboardEvent)=>voidunsubscribe:()=>void}const keyboard = (value:string) => {let key:keyProps = {value: value,isDown: false,isUp: true,press: undefined,release: undefined,downHandler: event => {if (event.key === key.value) {if (key.isUp && key.press)key.press();key.isDown = true;key.isUp = false;event.preventDefault();}},upHandler: event => {if (event.key === key.value) {if (key.isDown && key.release) key.release();key.isDown = false;key.isUp = true;event.preventDefault();}},unsubscribe: () => {window.removeEventListener("keydown", downListener);window.removeEventListener("keyup", upListener);}};const downListener = key.downHandler.bind(key);const upListener = key.upHandler.bind(key);window.addEventListener("keydown", downListener, false);window.addEventListener("keyup", upListener, false);return key;}export {keyboard,keyProps};
一段碰撞检测:
hitTestRectangle(r1: any, r2: any) {let hit, combinedHalfWidths, combinedHalfHeights, vx, vy;hit = false;r1.centerX = r1.x + r1.width / 2;r1.centerY = r1.y + r1.height / 2;r2.centerX = r2.x + r2.width / 2;r2.centerY = r2.y + r2.height / 2;r1.halfWidth = r1.width / 2;r1.halfHeight = r1.height / 2;r2.halfWidth = r2.width / 2;r2.halfHeight = r2.height / 2;vx = r1.centerX - r2.centerX;vy = r1.centerY - r2.centerY;combinedHalfWidths = r1.halfWidth + r2.halfWidth;combinedHalfHeights = r1.halfHeight + r2.halfHeight;if (Math.abs(vx) < combinedHalfWidths) {if (Math.abs(vy) < combinedHalfHeights) {hit = true;} else {hit = false;}} else {hit = false;}return hit;}
