# pixi

Pixi是一个超快的2D渲染引擎

<!DOCTYPE html>
<html lang="zn">

<head>
    <meta charset="UTF-8">
    <title>Pixi JS 置换滤镜效果</title>
    <style>
        .start-btn,
        .stop-btn {
            display: inline-block;
            color: #fff;
            border-radius: 4px;
            border: none;
            cursor: pointer;
            outline: none;
            padding: 10px 20px;
            margin-bottom: 30px;
        }

        .start-btn {
            background-color: #ff0081;
            box-shadow: 0 2px 25px rgba(255, 0, 130, 0.5);
        }

        .stop-btn {
            background-image: linear-gradient(to right, #4facfe 0%, #00f2fe 100%);
            margin-left: 20px;
            box-shadow: 0 2px 25px rgba(22, 217, 227, 0.5);
        }
    </style>
</head>

<body>
    <div>
        <button class="start-btn">开始</button>
        <button class="stop-btn">停止</button>
    </div>
    <div id="px-render"></div>

    <script src="https://www.kkkk1000.com/js/pixi4.8.2.js"></script>
    <script>
        // 创建一个 Pixi应用 需要的一些参数
        var option = {
            width: 400,
            height: 300,
            transparent: true,
        }

        // 创建一个 Pixi应用
        var app = new PIXI.Application(option);
        // 获取渲染器
        var renderer = app.renderer;
        // 图片精灵
        var preview;
        // 置换图精灵
        var displacementSprite;
        // 滤镜
        var displacementFilter;
        // 舞台(一个容器),这里面包括了图片精灵、置换图精灵
        var stage;
        var playground = document.getElementById('px-render');

        function setScene(url) {
            // renderer.view 是 Pixi 创建的一个canvas
            // 把 Pixi 创建的 canvas 添加到页面上
            playground.appendChild(renderer.view);

            // 创建一个容器 
            stage = new PIXI.Container();

            // 根据图片的 url,创建图片精灵
            preview = PIXI.Sprite.fromImage(url);

            // 创建置换图精灵,在创建置换滤镜时会用到这个精灵 
            displacementSprite = PIXI.Sprite.fromImage(
			'https://www.kkkk1000.com/images/learnPixiJS/sprite.png'); 

            // 设置置换图精灵为平铺模式
            displacementSprite.texture.baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT;

            // 创建一个置换滤镜
            displacementFilter = new PIXI.filters.DisplacementFilter(displacementSprite);

            // 添加 图片精灵 到舞台
            stage.addChild(preview);

            // 添加 置换图精灵 到舞台 
            stage.addChild(displacementSprite);

            // 把 stage 添加到根容器上
            app.stage.addChild(stage);
        }


        // 置换图精灵的移动速度
        var velocity = .8;
        // raf 是调用 requestAnimationFrame方法的返回值,停止动画效果时需要用到
        var raf;
        function animate() {
            raf = requestAnimationFrame(animate);
            // 改变置换图精灵的位置
            displacementSprite.x += velocity;
            displacementSprite.y += velocity;
        }
        setScene('https://www.kkkk1000.com/images/learnPixiJS/view.jpg');


        var start = document.querySelector('.start-btn');
        var stop = document.querySelector('.stop-btn');
        start.onclick = function () {
            // 设置舞台的滤镜
            stage.filters = [displacementFilter];
            // 开始动画
            animate();
        }

        stop.onclick = function () {
            // 取消滤镜
            stage.filters = [];
            // 停止动画
            cancelAnimationFrame(raf);
        }
    </script>
</body>

</html>

# 创建

//Create a Pixi Application
let app = new PIXI.Application({width: 256, height: 256});

//Add the canvas that Pixi automatically created for you to the HTML document
document.body.appendChild(app.view);

PIXI.Application算出了应该使用Canvas还是WebGL去渲染图象,它取决于你正在使用的浏览器支持哪一个。它的参数是一个被称作options的对象。

let app = new PIXI.Application({
    width: 256,         // default: 800
    height: 256,        // default: 600
    antialias: true,    // default: false
    transparent: false, // default: false
    resolution: 1       // default: 1
  }
);

如果你需要在你创建canvas标签之后改变它的背景色,设置 app.renderer对象的backgroundColor属性为一个任何的十六进制颜色:

app.renderer.backgroundColor = 0x061639;

画布的宽高,使用app.renderer.view.width 和app.renderer.view.height。

使用画布的resize方法可以改变canvas的大小,提供任何新的width 和 height变量给他都行。但是为了确认宽高的格式正确,将autoResize设置为true。

app.renderer.autoResize = true;
app.renderer.resize(512, 512);

# Pixi 精灵

在画布上显示的东西必须被加进一个被称作 舞台的Pixi对象中。你能够像这样使用舞台对象:

app.stage

这个舞台是一个Pixi 容器对象。你能把它理解成一种将放进去的东西分组并存储的空箱子。 舞台对象是在你的场景中所有可见对象的根容器。所有放进去的东西都会被渲染到canvas中。

所以可以放些什么到舞台上呢?那就是被称作 精灵 的特殊图像对象。精灵是你能用代码控制图像的基础。你能够控制他们的位置,大小,和许多其他有用的属性来产生交互和动画。如果知道怎么创建精灵和把他们添加进舞台,离做出一个游戏就仅仅剩下一步之遥!

Pixi拥有一个精灵类来创建游戏精灵。有三种主要的方法来创建它:

  • 用一个单图像文件创建。
  • 用一个 雪碧图 来创建。雪碧图是一个放入了你游戏所需的所有图像的大图。
  • 从一个纹理贴图集中创建。(纹理贴图集就是用JSON定义了图像大小和位置的雪碧图)

# 将图片加载到纹理缓存中

因为Pixi用WebGL和GPU去渲染图像,所以图像需要转化成GPU可以处理的版本。可以被GPU处理的图像被称作 纹理 。在让精灵显示图片之前,需要将普通的图片转化成WebGL纹理。为了让所有工作执行的快速有效率,Pixi使用 纹理缓存 来存储和引用所有你的精灵需要的纹理。纹理的名称字符串就是图像的地址。这意味着如果有从"images/cat.png"加载的图像,你可以在纹理缓存中这样找到他:

PIXI.utils.TextureCache["images/cat.png"];

纹理被以WEBGL兼容的格式存储起来,它可以使Pixi的渲染有效率的进行。你现在可以使用Pixi的精灵类来创建一个新的精灵,让它使用纹理。

let texture = PIXI.utils.TextureCache["images/anySpriteImage.png"];
let sprite = new PIXI.Sprite(texture);

但是该怎么加载图像并将它转化成纹理?答案是用Pixi已经构建好的loader对象。

Pixi强大的loader对象可以加载任何你需要种类的图像资源。这里展示了怎么加载一个图像并在加载完成时用一个叫做setup的方法来使用它。

PIXI.loader
  .add("images/anyImage.png")
  .load(setup);

function setup() {
  //This code will run when the loader has finished loading the image
}]

Pixi的最佳实践 如果使用了Loader,你就应该创建一个精灵来连接loader的resources对象,像下面这样:

let sprite = new PIXI.Sprite(
  PIXI.loader.resources["images/anyImage.png"].texture
);

这里是一个完整的加载图像的代码。调用setup方法,并为加载的图像创建一个精灵。

PIXI.loader
  .add("images/anyImage.png")
  .load(setup);

function setup() {
  let sprite = new PIXI.Sprite(
    PIXI.loader.resources["images/anyImage.png"].texture
  );
}

这是这个教程之中用来加载图像和创建精灵的通用方法。

你可以链式调用add方法来加载一系列图像,像下面这样:

PIXI.loader
  .add("images/imageOne.png")
  .add("images/imageTwo.png")
  .add("images/imageThree.png")
  .load(setup);

更好的方式则是用数组给一个add方法传参,像这样:

PIXI.loader
  .add([
    "images/imageOne.png",
    "images/imageTwo.png",
    "images/imageThree.png"
  ])
  .load(setup);

这个loader也允许你使用JSON文件,关于JSON文件你应该已经在前面学过了。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title></title>
		<style>
			*{
				margin:0;
				padding:0;
			}
		</style>
	</head>
	<body>
		
	</body>
</html>
 <script src="./pixi.js"></script>
<script type="text/javascript">
let app = new PIXI.Application({
    width: 256,
    height: 256,                       
    antialias: true,
    transparent: false,
    resolution: 1
  }
);

//Add the canvas that Pixi automatically created for you to the HTML document
document.body.appendChild(app.view);

//load an image and run the `setup` function when it's done
PIXI.loader
  .add("./cat.png")
  .load(setup);

//This `setup` function will run when the image has loaded
function setup() {

  //Create the cat sprite
  let cat = new PIXI.Sprite(PIXI.loader.resources["./cat.png"].texture);

  //Add the cat to the stage
  app.stage.addChild(cat);
  setInterval(()=>{
	app.stage.removeChild(cat)
  },5000)
  
}
</script>


如果想把一个精灵从舞台上挪走,就可以使用removeChild方法:

app.stage.removeChild(anySprite)

但是通常,我们都把精灵的visible属性设置成false来让精灵简单的隐藏。

anySprite.visible = false;

# 使用别名

使用频繁的Pixi对象和方法设置一些简略的可读性更强的别名

//Aliases
let Application = PIXI.Application,
    loader = PIXI.loader,
    resources = PIXI.loader.resources,
    Sprite = PIXI.Sprite;

//Create a Pixi Application
let app = new Application({
    width: 256,
    height: 256,                       
    antialias: true,
    transparent: false,
    resolution: 1
  }
);

//Add the canvas that Pixi automatically created for you to the HTML document
document.body.appendChild(app.view);

//load an image and run the `setup` function when it's done
loader
  .add("images/cat.png")
  .load(setup);

//This `setup` function will run when the image has loaded
function setup() {

  //Create the cat sprite
  let cat = new Sprite(resources["images/cat.png"].texture);

  //Add the cat to the stage
  app.stage.addChild(cat);
}
# 使用普通的javaScript Img对象或canvas创建一个精灵

为了优化和效率我们常常选择从预加载的纹理缓存的纹理之中创建精灵。但是如果因为某些原因你需要从JavaScript的Image对象之中创建,可以使用Pixi的BaseTexture和Texture类:

let base = new PIXI.BaseTexture(anyImageObject),
    texture = new PIXI.Texture(base),
    sprite = new PIXI.Sprite(texture);

使用BaseTexture.fromCanvas从任何已经存在canvas标签中创建纹理:

let base = new PIXI.BaseTexture.fromCanvas(anyCanvasElement)

想改变已经显示的精灵的纹理,使用texture属性,可以设置任何Texture对象,像下面这样:

anySprite.texture = PIXI.utils.TextureCache["anyTexture.png"];
# 给加载的文件设置别名

只需要在add方法中第一个参数位置传进去这个别名就行了,举例来说,下面实现了怎么给这个猫的图片重命名为catImage。

PIXI.loader
  .add("catImage", "images/cat.png")
  .load(setup);
let cat = new PIXI.Sprite(PIXI.loader.resources.catImage.texture);

然而,建议永远别用这个操作!使用路径命名,处理的更简单和更少错误。

# 监视加载进程

Pixi的加载器有一个特殊的 progress 事件,它将会调用一个可以定制的函数,这个函数将在每次文件加载时调用。progress事件将会被loader的on方法调用,像是这样:

PIXI.loader.on("progress", loadProgressHandler);

这里展示了怎么将on方法注入加载链中,并且每当文件加载时调用一个用户定义的名叫loadProgressHandler的函数。

PIXI.loader
  .add([
    "images/one.png",
    "images/two.png",
    "images/three.png"
  ])
  .on("progress", loadProgressHandler)
  .load(setup);

function loadProgressHandler() {
  console.log("loading");
}

function setup() {
  console.log("setup");
}

每一个文件加载,progress事件调用loadProgressHandler函数在控制台输出 "loading"。当三个文件都加载完毕,setup方法将会运行,下面是控制台的输出:

loading
loading
loading
setup

这就不错了,不过还能变的更好。你可以知道哪个文件被加载了以及有百分之多少的文件被加载了。你可以在loadProgressHandler增加loader参数和resource参数实现这个功能,像下面这样:

function loadProgressHandler(loader, resource) { /*...*/ }

你现在可以使用 resource.url变量来找到现在已经被加载的文件。(如果你想找到你定义的别名,使用resource.name参数。)你可以使用loader.progress来找到现在有百分之多少的文件被加载了,这里有一些关于上面描述的代码:

PIXI.loader
  .add([
    "images/one.png",
    "images/two.png",
    "images/three.png"
  ])
  .on("progress", loadProgressHandler)
  .load(setup);

function loadProgressHandler(loader, resource) {

  //Display the file `url` currently being loaded
  console.log("loading: " + resource.url);

  //Display the percentage of files currently loaded
  console.log("progress: " + loader.progress + "%");

  //If you gave your files names as the first argument
  //of the `add` method, you can access them like this
  //console.log("loading: " + resource.name);
}

function setup() {
  console.log("All files loaded");
}
//这里是程序运行后的控制台显示:

//loading: images/one.png
//progress: 33.333333333333336%
//loading: images/two.png
//progress: 66.66666666666667%
//loading: images/three.png
//progress: 100%
//All files loaded

这实在太酷了!因为你能用这个玩意做个进度条出来。 (注意:还有一些额外的resource对象属性, resource.error会告诉你有哪些加载时候的错误,resource.data将会给你文件的原始二进制数据。)

# 一些关于Pixi的加载器的其他知识

Pixi的加载器有很多可以设置的功能:

add 方法有四个基础参数:

add(name, url, optionObject, callbackFunction)

这里有文档里面对这些参数的描述:

  • name (string): 加载源文件的别名,如果没设置,url就会被放在这.
  • url (string): 源文件的地址,是加载器 baseUrl的相对地址.
  • options (object literal): 加载设置.
  • options.crossOrigin (Boolean): 源文件请求跨域不?默认是自动设定的。
  • options.loadType: 源文件是怎么加载进来的?默认是Resource.LOAD_TYPE.XHR。options.xhrType: 用XHR的时候该怎么处理数据? 默认是Resource.XHR_RESPONSE_TYPE.DEFAULT。 callbackFunction: 当这个特定的函数加载完,这个特定的函数将会被执行。

只有url必填(你总得加载个文件吧。)

这里有点用了add方法加载文件的例子。第一个就是文档里所谓的“正常语法”:

.add('key', 'http://...', function () {})
.add('http://...', function () {})
.add('http://...')

这些就是所谓“对象语法”啦:

.add({
  name: 'key2',
  url: 'http://...'
}, function () {})

.add({
  url: 'http://...'
}, function () {})

.add({
  name: 'key3',
  url: 'http://...'
  onComplete: function () {}
})

.add({
  url: 'https://...',
  onComplete: function () {},
  crossOrigin: true
})

你也可以给add方法传一个对象的数组,或者既使用对象数组,又使用链式加载:

.add([
  {name: 'key4', url: 'http://...', onComplete: function () {} },
  {url: 'http://...', onComplete: function () {} },
  'http://...'
]);

(注意:如果你需要重新加载一批文件,调用加载器的reset方法:PIXI.loader.reset();)

# 精灵位置

可以通过改变它的x和y坐标的值来改变他们的位置。下面的例子就是你通过设置x和y为96坐标让它在舞台上居中。

cat.x = 96;
cat.y = 96;

在你创建这个精灵之后,把这两行代码放进setup方法。

function setup() {

  //Create the `cat` sprite
  let cat = new Sprite(resources["images/cat.png"].texture);

  //Change the sprite's position
  cat.x = 96;
  cat.y = 96;

  //Add the cat to the stage so you can see it
  app.stage.addChild(cat);
}

(注意:在这个例子里,Sprite是 PIXI.Sprite的别名,TextureCache是PIXI.utils.TextureCache的别名,resources是PIXI.loader.resources的别名,我从现在开始在代码中使用这些别名。)

这两行代码将把猫往右移动96像素,往下移动96像素。 可以一句话设置精灵的x和y:

sprite.position.set(x, y)

# 大小和比例 旋转

控制宽高

cat.width = 80;
cat.height = 120;

精灵都有scale.x 和 scale.y属性,他们可以成比例的改变精灵的宽高。这里的例子把猫的大小变成了一半:

cat.scale.x = 0.5;
cat.scale.y = 0.5;

Pixi可以用一行代码缩放你的精灵,那要用到scale.set方法。

cat.scale.set(0.5, 0.5);

可以通过对一个精灵的rotation设定一个角度来旋转它。

cat.rotation = 0.5;

精灵的左上角代表它的位置,这个点被称之为 锚点 。如果你用像0.5这种值设定rotation,这个旋转将会 围绕着锚点发生 。

通过改变精灵的anchor属性的xy值来实现。像下面这样:

cat.anchor.x = 0.5;
cat.anchor.y = 0.5;

anchor.x和anchor.y的值如果是从0到1,就会被认为是整个纹理的长度或宽度百分比。设置他们都为0.5,锚点就处在了图像中心。精灵定位的依据点不会改变,锚点的改变是另外一回事。

像是position和scale属性一样,你也可以在一行内像这样设置锚点的位置:

cat.anchor.set(x, y)

精灵也提供和anchor差不多的pivot属性来设置精灵的原点。如果你改变了它的值之后旋转精灵,它将会围绕着你设置的原点来旋转。举个例子,下面的代码将精灵的pivot.x和pivot.y设置为了32。

cat.pivot.set(32, 32) 假设精灵图是64x64像素,它将绕着它的中心点旋转。但是记住:你如果改变了精灵的pivot属性,你也就改变了它的原点位置。

所以anchor 和 pivot的不同之处在哪里呢?他们真的很像!anchor改变了精灵纹理的图像原点,用0到1的数据来填充。pivot则改变了精灵的原点,用像素的值来填充。

# 雪碧图创建精灵

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title></title>
		<style>
			*{
				margin:0;
				padding:0;
			}
		</style>
	</head>
	<body>
		
	</body>
</html>
 <script src="./pixi.js"></script>
<script type="text/javascript">	
//Aliases
let Application = PIXI.Application,
    loader = PIXI.loader,
    resources = PIXI.loader.resources,
	Rectangle = PIXI.Rectangle,
	TextureCache= PIXI.TextureCache,
    Sprite = PIXI.Sprite;	
	
	
	
let app = new PIXI.Application({
    width: 256,
    height: 256,                       
    antialias: true,
    transparent: false,
    resolution: 1,
	backgroundColor:0XFFFFFF
  }
);

//Add the canvas that Pixi automatically created for you to the HTML document
document.body.appendChild(app.view);

//load an image and run the `setup` function when it's done
PIXI.loader
  .add("./09.png")
  .load(setup);
  
function setup() {

 //Create the `tileset` sprite from the texture
  let texture = TextureCache["./09.png"];

  //Create a rectangle object that defines the position and
  //size of the sub-image you want to extract from the texture
  //(`Rectangle` is an alias for `PIXI.Rectangle`)
  let rectangle = new Rectangle(96, 64, 32, 32);
  //(x位置,y位置,width,height)

  //Tell the texture to use that rectangular section
  texture.frame = rectangle;

  //Create the sprite from the texture
  let rocket = new Sprite(texture);

  //Position the rocket sprite on the canvas
  rocket.x = 32;
  rocket.y = 32;

  //Add the rocket to the stage
  app.stage.addChild(rocket);

  
}
</script>

Pixi内置了一个通用的Rectangle对象 (PIXI.Rectangle),他是一个用于定义矩形形状的通用对象。他需要一些参数,前两个参数定义了x 和y轴坐标位置,后两个参数定义了矩形的width 和 height,下面是新建一个Rectangle对象的格式。

let rectangle = new PIXI.Rectangle(x, y, width, height);

这个矩形对象仅仅是一个 数据对象,如何使用它完全取决于你。在我们的例子里,我们用它来定义子图像在雪碧图中的位置和大小。Pixi的纹理中有一个叫做frame的很有用的属性,它可以被设置成任何的Rectangle对象。frame将纹理映射到Rectangle的维度。下面是怎么用frame来定义火箭的大小和位置。

let rectangle = new Rectangle(192, 128, 64, 64);
texture.frame = rectangle;

你现在可以用它裁切纹理来创建精灵了:

let rocket = new Sprite(texture);

# 移动精灵

使用Pixi的ticker。这被称为 游戏循环 。任何在游戏循环里的代码都会1秒更新60次。你可以用下面的代码让 cat 精灵以每帧1像素的速率移动。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title></title>
		<style>
			*{
				margin:0;
				padding:0;
			}
		</style>
	</head>
	<body>
		
	</body>
</html>
 <script src="./pixi.js"></script>
<script type="text/javascript">	
//Aliases
let Application = PIXI.Application,
    Container = PIXI.Container,
    loader = PIXI.loader,
    resources = PIXI.loader.resources,
    TextureCache = PIXI.utils.TextureCache,
    Sprite = PIXI.Sprite,
    Rectangle = PIXI.Rectangle;

//Create a Pixi Application
let app = new Application({
    width: 256,
    height: 256,                       
    antialias: true,
    transparent: false,
    resolution: 1
  }
);

//Add the canvas that Pixi automatically created for you to the HTML document
document.body.appendChild(app.view);

loader
  .add("./cat.png")
  .load(setup);

//Define any variables that are used in more than one function
let cat;

function setup() {

  //Create the `cat` sprite
  cat = new Sprite(resources["./cat.png"].texture);
  cat.y = 96;
  app.stage.addChild(cat);

  //Start the game loop
  app.ticker.add(delta => gameLoop(delta));
}

function gameLoop(delta){

  //Move the cat 1 pixel
  cat.x += 1;

  //Optionally use the `delta` value
  //cat.x += 1 + delta;
}
</script>

# 速度属性

vx和 vy去控制精灵的运动速度。 vx被用来设置精灵在x轴(水平)的速度和方向。vy被用来设置精灵在y轴(垂直)的速度和方向。

function setup() {

  //Create the `cat` sprite
  cat = new Sprite(resources["images/cat.png"].texture);
  cat.y = 96;
  cat.vx = 0;
  cat.vy = 0;
  app.stage.addChild(cat);

  //Start the game loop
  app.ticker.add(delta => gameLoop(delta));
}

function gameLoop(delta){

  //Update the cat's velocity
  cat.vx = 1;
  cat.vy = 1;

  //Apply the velocity values to the cat's
  //position to make it move
  cat.x += cat.vx;
  cat.y += cat.vy;
}

# 键盘控制

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<title></title>
		<style>
			*{
				margin:0;
				padding:0;
			}
		</style>
	</head>
	<body>
		
	</body>
</html>
 <script src="./pixi.js"></script>
<script type="text/javascript">	
//Define any variables that are used in more than one function
let cat, state;
let Application = PIXI.Application,
    Container = PIXI.Container,
    loader = PIXI.loader,
    resources = PIXI.loader.resources,
    TextureCache = PIXI.utils.TextureCache,
    Sprite = PIXI.Sprite,
    Rectangle = PIXI.Rectangle;

//Create a Pixi Application
let app = new Application({
    width: 256,
    height: 256,                       
    antialias: true,
    transparent: false,
    resolution: 1
  }
);

//Add the canvas that Pixi automatically created for you to the HTML document
document.body.appendChild(app.view);
loader
  .add("./cat.png")
  .load(setup);
function setup() {

  //Create the `cat` sprite
  cat = new Sprite(resources["./cat.png"].texture);
  cat.y = 96;
  cat.vx = 0;
  cat.vy = 0;
  app.stage.addChild(cat);

  //Capture the keyboard arrow keys
  let left = keyboard(37),
      up = keyboard(38),
      right = keyboard(39),
      down = keyboard(40);

  //Left arrow key `press` method
  left.press = () => {
    //Change the cat's velocity when the key is pressed
    cat.vx = -5;
    cat.vy = 0;
  };

  //Left arrow key `release` method
  left.release = () => {
    //If the left arrow has been released, and the right arrow isn't down,
    //and the cat isn't moving vertically:
    //Stop the cat
    if (!right.isDown && cat.vy === 0) {
      cat.vx = 0;
    }
  };

  //Up
  up.press = () => {
    cat.vy = -5;
    cat.vx = 0;
  };
  up.release = () => {
    if (!down.isDown && cat.vx === 0) {
      cat.vy = 0;
    }
  };

  //Right
  right.press = () => {
    cat.vx = 5;
    cat.vy = 0;
  };
  right.release = () => {
    if (!left.isDown && cat.vy === 0) {
      cat.vx = 0;
    }
  };

  //Down
  down.press = () => {
    cat.vy = 5;
    cat.vx = 0;
  };
  down.release = () => {
    if (!up.isDown && cat.vx === 0) {
      cat.vy = 0;
    }
  };

  //Set the game state
  state = play;

  //Start the game loop
  app.ticker.add(delta => gameLoop(delta));
}

function gameLoop(delta){

  //Update the current game state:
  state(delta);
}

function keyboard(keyCode) {
  let key = {};
  key.code = keyCode;
  key.isDown = false;
  key.isUp = true;
  key.press = undefined;
  key.release = undefined;
  //The `downHandler`
  key.downHandler = event => {
    if (event.keyCode === key.code) {
      if (key.isUp && key.press) key.press();
      key.isDown = true;
      key.isUp = false;
    }
    event.preventDefault();
  };

  //The `upHandler`
  key.upHandler = event => {
    if (event.keyCode === key.code) {
      if (key.isDown && key.release) key.release();
      key.isDown = false;
      key.isUp = true;
    }
    event.preventDefault();
  };

  //Attach event listeners
  window.addEventListener(
    "keydown", key.downHandler.bind(key), false
  );
  window.addEventListener(
    "keyup", key.upHandler.bind(key), false
  );
  return key;
}


function play(delta) {

  //Use the cat's velocity to make it move
  cat.x += cat.vx;
  cat.y += cat.vy
}
setup()
</script>

# 三种方式从已经加载的纹理贴图集中创建精灵:

  • 使用 TextureCache:
let texture = TextureCache["frameId.png"],
    sprite = new Sprite(texture);
  • 如果你是使用的 loader来加载纹理贴图集, 使用loader的 resources:
let sprite = new Sprite(
  resources["images/treasureHunter.json"].textures["frameId.png"]
);
  • 要创建一个精灵需要输入太多东西了! 所以我建议你给纹理贴图集的textures对象创建一个叫做id的别名,象是这样:
let id = PIXI.loader.resources["images/treasureHunter.json"].textures;
//现在你就可以像这样实例化一个精灵了:
let sprite = new Sprite(id["frameId.png"]);

# 给精灵分组

分组让你能够让你创建游戏场景,并且像一个单一单元那样管理相似的精灵图。Pixi有一个对象叫 Container,它可以帮你做这些工作。让我们弄清楚它是怎么工作的。

想象一下你想展示三个精灵:一只猫,一只刺猬和一只老虎。创建它们,然后设置它们的位置 - 但是不要把它们添加到舞台上。

//The cat
let cat = new Sprite(id["cat.png"]);
cat.position.set(16, 16);

//The hedgehog
let hedgehog = new Sprite(id["hedgehog.png"]);
hedgehog.position.set(32, 32);

//The tiger
let tiger = new Sprite(id["tiger.png"]);
tiger.position.set(64, 64);
//然后创建一个animals容器像这样去把他们聚合在一起:

let animals = new Container();
//然后用 addChild 去把精灵图 添加到分组中 。

animals.addChild(cat);
animals.addChild(hedgehog);
animals.addChild(tiger);
最后把分组添加到舞台上。

app.stage.addChild(animals);
(stage对象也是一个Container。它是所有Pixi精灵的根容器。)

不过你现在可以像对待一个单一单元一样对待animals分组。你可以把Container当作是一个特殊类型的不包含任何纹理的精灵。

如果你需要获取animals包含的所有子精灵,你可以用它的children数组获取。

console.log(animals.children)
//Displays: Array [Object, Object, Object]

因为animals分组跟其他精灵一样,你可以改变它的x和y的值,alpha, scale和其他精灵的属性。

animals.position.set(64, 64);

整个分组的精灵都会向右和向下移动64像素。 animals分组也有它自己的尺寸,它是以包含的精灵所占的区域计算出来的。你可以像这样来获取width和height的值:

console.log(animals.width);
//Displays: 112
# 局部位置和全局位置
console.log(cat.x);
//Displays: 16//猫咪在animals容器的局部位置
//parentSprite.toGlobal(childSprite.position)
console.log(animals.toGlobal(cat.position));
//Displays: Object {x: 80, y: 80...};

如果想知道一个精灵的全局位置,但是不知道精灵的父容器怎么办?每个精灵图有一个属性叫parent 能告诉精灵的父级是什么。在上面的例子中,猫的父级是 animals。这意味着你可以像如下代码一样得到猫的全局位置:

cat.parent.toGlobal(cat.position);

这还有一种方式能够计算出全局位置!而且,它实际上最好的方式,所以听好啦!如果想知道精灵到canvas左上角的距离,但是不知道或者不关心精灵的父亲是谁,用getGlobalPosition方法。这里展示如何用它来找到老虎的全局位置:

tiger.getGlobalPosition().x
tiger.getGlobalPosition().y

如果想转换全局位置为局部位置怎么办?你可以用toLocal方法。它的工作方式类似,但是通常是这种通用的格式:

sprite.toLocal(sprite.position, anyOtherSprite)

用 toLocal 找到一个精灵和其他任何一个精灵之间的距离。这段代码告诉你如何获取老虎的相对于猫头鹰的局部位置。

tiger.toLocal(tiger.position, hedgehog).x
tiger.toLocal(tiger.position, hedgehog).y

上面的代码会返回给你一个32的x值和一个32的y值。你可以在例子中看到老虎的左上角和猫头鹰的左上角距离32像素。

# 绘制图形

  • 矩形 所有的形状的初始化都是先创造一个Pixi的Graphics的类 (PIXI.Graphics)的实例。

let rectangle = new Graphics(); 调用beginFill和一个16进制的颜色值来设置矩形的填充颜色。下面展示如何设置颜色为淡蓝色。

rectangle.beginFill(0x66CCFF); 如果你想要给图形设置一个轮廓,使用lineStyle方法。下面展示如何给矩形设置一个4像素宽alpha值为1的红色轮廓

rectangle.lineStyle(4, 0xFF3300, 1); 调用drawRect方法来画一个矩形。它的四个参数是x, y, width 和 height。

rectangle.drawRect(x, y, width, height); 调用endFill结束绘制。

rectangle.endFill();

let rectangle = new Graphics();
rectangle.lineStyle(4, 0xFF3300, 1);
rectangle.beginFill(0x66CCFF);
rectangle.drawRect(0, 0, 64, 64);
rectangle.endFill();
rectangle.x = 170;
rectangle.y = 170;
app.stage.addChild(rectangle);
//这些代码可以在(170,170)这个位置创造一个宽高都为64的蓝色的红框矩形。
  • 圆形
drawCircle(x, y, radius)

一个圆形的x和y坐标也是它自身的圆点

  • 椭圆
drawEllipse(x, y, width, height)

x/y坐标位置决定了椭圆的左上角(想象椭圆被一个不可见的矩形边界盒包围着-盒的左上角代表了椭圆x/y的锚点位置)。下面是50像素宽20像素高的黄色椭圆。

  • 圆角矩形
drawRoundedRect(x, y, width, height, cornerRadius)
  • 线段
let line = new Graphics();
line.lineStyle(4, 0xFFFFFF, 1);
line.moveTo(0, 0);
line.lineTo(80, 50);
line.x = 32;
line.y = 32;
app.stage.addChild(line);
  • 多边形
  • 可以使用drawPolygon方法来将线段连接起来并且填充颜色来创造复杂图形。drawPolygon的参数是一个路径数组,数组中的值为决定图形上每个点位置的x/y坐标。
let path = [
  point1X, point1Y,
  point2X, point2Y,
  point3X, point3Y
];

graphicsObject.drawPolygon(path);
  • 显示文本
let message = new Text("Hello Pixi!");
message.position.set(54, 96);
app.stage.addChild(message);

但是如果你想要更绚丽的文字,使用Pixi的TextStyle函数来自定义文字效果。下面展示如何操作:

let style = new TextStyle({
  fontFamily: "Arial",
  fontSize: 36,
  fill: "white",
  stroke: '#ff3300',
  strokeThickness: 4,
  dropShadow: true,
  dropShadowColor: "#000000",
  dropShadowBlur: 4,
  dropShadowAngle: Math.PI / 6,
  dropShadowDistance: 6,
});

添加style对象作为Text函数的第二个参数来应用样式到文本上,就像这样:

let message = new Text("Hello Pixi!", style);

注意

如果上述代码因为某些元素报错,可能是因为没有引入别名

let Application = PIXI.Application,
    Container = PIXI.Container,
    loader = PIXI.loader,
    resources = PIXI.loader.resources,
    TextureCache = PIXI.utils.TextureCache,
    Sprite = PIXI.Sprite,
	Graphics = PIXI.Graphics,
	Text=PIXI.Text,
	TextStyle=PIXI.TextStyle,
    Rectangle = PIXI.Rectangle;
最后更新: 8/14/2019, 4:29:54 PM