PIXIJS超级详细教程【从入门到入土-下】

来自GitHub教程 GitHub - Zainking/LearningPixi: ⚡️Pixi教程中文版

PIXIJS教程【从入门到入土-上】地址【https://blog.csdn.net/qq_61672548/article/details/127253760】

5.2 加载纹理贴图集

可以使用Pixi的loader来加载纹理贴图集。如果是用Texture Packer生成的JSON,loader会自动读取数据,并对每一个帧创建纹理。下面就是怎么用loader来加载treasureHunter.json。当它成功加载,setup方法将会执行

loader
  .add("images/treasureHunter.json")
  .load(setup);

现在每一个图像的帧都被加载进Pixi的纹理缓存之中了。你可以使用Texture Packer中定义的他们的名字来取用每一个纹理。

如果你是使用的 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"]);

真不错啊~!

六、移动精灵

6.1 移动

现在你知道了如何展示精灵,但是让它们移动呢?很简单:使用Pixi的ticker。这被称为 游戏循环 。任何在游戏循环里的代码都会1秒更新60次。你可以用下面的代码让 cat 精灵以每帧1像素的速率移动。

let icon
function setup() {
    
    
    let id = resources["./images/treasureHunter.json"].textures
    icon = new Sprite(id["icon.png"])
    app.stage.addChild(icon)
    //定义游戏循环
    app.ticker.add(animation)
}

function animation() {
    
    
    icon.x++
}

你也没必要非得用Pixi的ticker来创建游戏循环。如果你喜欢,也可以用requestAnimationFrame像这样创建:

function gameLoop() {
    
    

  //Call this `gameLoop` function on the next screen refresh
  //(which happens 60 times per second)
  requestAnimationFrame(gameLoop);

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

//Start the loop
gameLoop();

(注意 cat 变量需要在setupgameLoop函数之外定义,然后你可以在全局中任何地方都能获取到它们)

你可以让精灵的位置,角度或者大小动起来 - 什么都可以!你会在下面看到更多精灵动画的例子。

6.2 速度属性

为了给你更多的灵活性,这里有两个 速度属性vxvy去控制精灵的运动速度。 vx被用来设置精灵在x轴(水平)的速度和方向。vy被用来设置精灵在y轴(垂直)的速度和方向。 他们可以直接更新速度变量并且给精灵设定这些速度值。这是一个用来让你更方便的更新交互式动画的额外的模块。

第一步是给你的精灵创建vxvy属性,然后给他们初始值。

cat.vx = 0;
cat.vy = 0;

vxvy设置为0表示精灵静止。

接下来,在游戏循环中,更新vxvy为你想让精灵移动的速度值。然后把这些值赋给精灵的xy属性。下面的代码讲明了你如何利用该技术让cat能够每帧向右下方移动一个像素:

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(gameLoop);
}

function gameLoop(){
    
    

  //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;
}

如果你想让猫往不同的方向移动怎么办?可以把它的 vx 赋值为 -1让猫向左移动。可以把它的 vy 赋值为 -1让猫向上移动。为了让猫移动的更快一点,把值设的更大一点,像3, 5, -2, 或者 -4。

你会在前面看到如何通过利用vxvy的速度值来模块化精灵的速度,它对游戏的键盘和鼠标控制系统很有帮助,而且更容易实现物理模拟。

七、给精灵分组

7.1 Container分组

分组让你能够让你创建游戏场景,并且像一个单一单元那样管理相似的精灵图。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 PIXI.Container();

然后用 addChild 去把精灵图 添加到分组中

animals.addChild(cat);
animals.addChild(hedgehog);
animals.addChild(tiger);

最后把分组添加到舞台上。

app.stage.addChild(animals);

(你知道的,stage对象也是一个Container。它是所有Pixi精灵的根容器。)

这就是上面代码的效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nFgkW4af-1665574697605)(https://github.com/Zainking/LearningPixi/raw/master/examples/images/screenshots/18.png)]

你是看不到这个包含精灵图的animals分组的。它仅仅是个容器而已。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XVkE8YKn-1665574697606)(https://github.com/Zainking/LearningPixi/raw/master/examples/images/screenshots/19.png)]

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

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

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

这告诉你animals有三个子精灵。

因为animals分组跟其他精灵一样,你可以改变它的xy的值,alpha, scale和其他精灵的属性。所有你改变了的父容器的属性值,都会改变它的子精灵的相应属性。所以如果你设置分组的xy的位置,所有的子精灵都会相对于分组的左上角重新定位。如果你设置了 animalsxy的位置为64会发生什么呢?

animals.position.set(64, 64);

整个分组的精灵都会向右和向下移动64像素。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ccUh7fQ-1665574697607)(https://github.com/Zainking/LearningPixi/raw/master/examples/images/screenshots/20.png)]

animals分组也有它自己的尺寸,它是以包含的精灵所占的区域计算出来的。你可以像这样来获取widthheight的值:

console.log(animals.width);
//Displays: 112

console.log(animals.height);
//Displays: 112

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nqRu3lhU-1665574697608)(https://github.com/Zainking/LearningPixi/raw/master/examples/images/screenshots/21.png)]

如果你改变了分组的宽和高会发生什么呢?

animals.width = 200;
animals.height = 200;

所有的孩子精灵都会缩放到刚才你设定的那个值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wjxt9EoF-1665574697608)(https://github.com/Zainking/LearningPixi/raw/master/examples/images/screenshots/22.png)]

如果你喜欢,你可以在一个 Container 里嵌套许多其他Container,如果你需要,完全可以创建一个更深的层次。然而,一个 DisplayObject (像 Sprite 或者其他 Container)只能一次属于一个父级。如果你用 addChild 让一个精灵成为其他精灵的孩子。Pixi会自动移除它当前的父级,这是一个不用你操心的有用的管理方式。

7.2 局部位置和全局位置

当你往一个Container添加一个精灵时,它的xy的位置是 相对于分组的左上角 的。这是精灵的局部位置,举个例子,你认为这个猫在这张图的哪个位置?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C5MDQRit-1665574697610)(https://github.com/Zainking/LearningPixi/raw/master/examples/images/screenshots/20.png)]

让我们看看:

console.log(cat.x);
//Displays: 16

16?是的!这因为猫的只往分组的左上角偏移了16个像素。16是猫的局部位置。

精灵图还有 全局位置 。全局位置是舞台左上角到精灵锚点(通常是精灵的左上角)的距离。你可以通过toGlobal方法的帮助找到精灵图的全局位置:

parentSprite.toGlobal(childSprite.position)

这意味着你能在animals分组里找到猫的全局位置:

console.log(animals.toGlobal(cat.position));
//Displays: Object {x: 80, y: 80...};

上面给你返回了xy的值为80。这正是猫相对于舞台左上角的相对位置,也就是全局位置。

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

cat.parent.toGlobal(cat.position);

即使你不知道猫的当前父级是谁,上面的代码依然能够正确工作。

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

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

它会给你返回xy的值为128。 特别的是,getGlobalPosition是高精度的:当精灵的局部位置改变的同时,它会返回给你精确的全局位置。我曾要求Pixi开发团队添加这个特殊的特性,以便于开发精确的碰撞检测游戏。(谢谢Matt和团队真的把他加上去了!)

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

sprite.toLocal(sprite.position, anyOtherSprite)

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

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

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

7.3 ParticleContainer 分组

Pixi有一个额外的,高性能的方式去分组精灵的方法称作:ParticleContainerPIXI.ParticleContainer)。任何在ParticleContainer 里的精灵都会比在一个普通的Container的渲染速度快2到5倍。这是用于提升游戏性能的一个很棒的方法。

可以像这样创建 ParticleContainer :

let superFastSprites = new PIXI.particles.ParticleContainer();

然后用 addChild 去往里添加精灵,就像往普通的 Container添加一样。

如果你决定用ParticleContainer你必须做出一些妥协。在 ParticleContainer 里的精灵图只有一小部分基本属性:x, y, width, height, scale, pivot, alpha, visible - 就这么多。而且,它包含的精灵不能再继续嵌套自己的孩子精灵。 ParticleContainer 也不能用Pixi的先进的视觉效果像过滤器和混合模式。每个 ParticleContainer 只能用一个纹理(所以如果你想让精灵有不同的表现方式你将不得不更换雪碧图)。但是为了得到巨大的性能提升,这些妥协通常是值得的。你可以在同一个项目中同时用 ContainerParticleContainer,然后微调一下你自己的优化

八、文本

使用一个 Text 对象 (PIXI.Text)在舞台上展示文本。简单来说,你可以这样使用它:

let message = new Text("Hello Pixi!");
app.stage.addChild(message);

这将会在画布上展示文本“Hello, Pixi”。Pixi的文本对象继承自Sprite类,所以它包含了所有相同的属性,像x, y, width, height, alpha, 和 rotation。你可以像处理其他精灵一样在舞台上定位或调整文本。例如,你可以像下面这样使用position.set来设置messagexy位置:

message.position.set(54, 96);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-68Ij0amm-1665574697611)(https://github.com/Zainking/LearningPixi/raw/master/examples/images/screenshots/24.png)]

这样你会得到基础的未加修饰的文本。但是如果你想要更绚丽的文字,使用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对象。所有样式属性,see here

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKl9zEOQ-1665574697611)(https://github.com/Zainking/LearningPixi/raw/master/examples/images/screenshots/24.5.png)]

如果你想要在你创建文本对象之后改变它的内容,使用text属性。

message.text = "Text changed!";

如果你想要重新定义样式属性,使用style属性。

message.style = {
    
    fill: "black", font: "16px PetMe64"};

九、碰撞检测

碰撞检测函数
hitTestRectangle 函数都有些什么呢?它做了什么,还有它是如何工作的?

function hitTestRectangle(r1, r2) {
    
    

  //Define the variables we'll need to calculate
  let hit, combinedHalfWidths, combinedHalfHeights, vx, vy;

  //hit will determine whether there's a collision
  hit = false;

  //Find the center points of each sprite
  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;

  //Find the half-widths and half-heights of each sprite
  r1.halfWidth = r1.width / 2;
  r1.halfHeight = r1.height / 2;
  r2.halfWidth = r2.width / 2;
  r2.halfHeight = r2.height / 2;

  //Calculate the distance vector between the sprites
  vx = r1.centerX - r2.centerX;
  vy = r1.centerY - r2.centerY;

  //Figure out the combined half-widths and half-heights
  combinedHalfWidths = r1.halfWidth + r2.halfWidth;
  combinedHalfHeights = r1.halfHeight + r2.halfHeight;

  //Check for a collision on the x axis
  if (Math.abs(vx) < combinedHalfWidths) {
    
    

    //A collision might be occuring. Check for a collision on the y axis
    if (Math.abs(vy) < combinedHalfHeights) {
    
    

      //There's definitely a collision happening
      hit = true;
    } else {
    
    

      //There's no collision on the y axis
      hit = false;
    }
  } else {
    
    

    //There's no collision on the x axis
    hit = false;
  }

  //`hit` will be either `true` or `false`
  return hit;
};

现在你知道了如何制造种类繁多的图形对象,但是你能用他们做什么?一个有趣的事情是利用它制作一个简单的 碰撞检测系统 。你可以用一个叫做:hitTestRectangle 的自定义的函数来检测两个矩形精灵是否接触。

hitTestRectangle(spriteOne, spriteTwo)

如果它们重叠, hitTestRectangle 会返回 true。你可以用 hitTestRectangle 结合 if 条件语句去检测两个精灵是否碰撞:

if (hitTestRectangle(cat, box)) {
    
    
  //There's a collision
} else {
    
    
  //There's no collision
}

正如你所见, hitTestRectangle 是走入游戏设计这片宇宙的大门。

运行在 examples 文件夹的 collisionDetection.html 文件,看看怎么用 hitTestRectangle工作。用方向按键去移动猫,如果猫碰到了盒子,盒子会变成红色,然后 “Hit!” 文字对象会显示出来。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dwYSnQwk-1665574697612)(https://github.com/Zainking/LearningPixi/raw/master/examples/images/screenshots/25.png)]

你已经看到了创建这些所有元素的代码,让猫移动的键盘控制。唯一的新的东西就是 hitTestRectangle 函数被用在 play 函数里检测碰撞。

function play(delta) {
    
    

  //use the cat's velocity to make it move
  cat.x += cat.vx;
  cat.y += cat.vy;

  //check for a collision between the cat and the box
  if (hitTestRectangle(cat, box)) {
    
    

    //if there's a collision, change the message text
    //and tint the box red
    message.text = "hit!";
    box.tint = 0xff3300;

  } else {
    
    

    //if there's no collision, reset the message
    //text and the box's color
    message.text = "No collision...";
    box.tint = 0xccff99;
  }
}

play 函数被每秒调用了60次,每一次这个 if 条件语句都会在猫和盒子之间进行碰撞检测。如果 hitTestRectangletrue,那么文字 message 对象会用 setText 方法去显示 “Hit”:

message.text = "Hit!";

这个盒子的颜色改变的效果是把盒子的 tint 属性改成一个16进制的红色的值实现的。

box.tint = 0xff3300;

如果没有碰撞,消息和盒子会保持它们的原始状态。

message.text = "No collision...";
box.tint = 0xccff99;

代码很简单,但是你已经创造了一个看起来完全活着的互动的世界!它简直跟魔术一样!令人惊讶的是,你大概已经拥有了你需要用Pixi制作游戏的全部技能!

>>> 2022.10.12 19:24 教程已经全部更新完,很大部分都是来自github 原文地址【https://github.com/Zainking/learningPixi】本来我只想做一个文档方便我自己在开发的时候查阅 然后觉得PIXIJS在国内的教程很少 便把此文章放到了CSDN上,能有机会帮助需要的人,因为很多朋友还是很少去国外找教程。PIXIJS还有很多其他很好的教程 【https://pixijs.com/tutorials/】去这里可以查看。

教程原文地址 GitHub - Zainking/LearningPixi: ⚡️Pixi教程中文版

附加

<<< 2022-10-17 21:52 添加一些PixiJS 开发常用API的使用方法,这部分全靠自己看官方文档和实践摸索,难度还是比较大的。官方API文档都是英文的,虽然浏览器带翻译,但是效果并不好,我感觉还不如不翻译,因为如果不是写在代码块的代码也会被翻译,有些变量名或者方法名写在代码块外,然后给翻译成中文,这会让你相当的蒙蔽~ 一些翻译意思也不到位。所以只有中英结合着看~

精灵表

官方教程【小精灵 API 文档 (pixijs.download)

在创建动画精灵中需要用到

实用程序类,用于维护对单个 Sprites 表中的纹理集合的引用。

要从代码访问子画面表,您可以将其JSON数据文件传递给Pixi的加载器:

PIXI.Loader.shared.add("images/spritesheet.json").load(setup);

function setup() {
    
    
  let sheet = PIXI.Loader.shared.resources["images/spritesheet.json"].spritesheet;
  ...
}

动画精灵

官方教程【PixiJS API Documentation

1. 创建精灵动画

1.1 创建精灵动画一般方法

注意和创建普通精灵不一样,注意差别 【Loader.shared】

PIXI.Loader.shared.add("./images/down.json").load(setup);

function setup() {
    
    
  let sheet = PIXI.Loader.shared.resources["./images/spritesheet.json"].spritesheet;
  let animatedSprite = new PIXI.AnimatedSprite(sheet.animations["down"]);
  ...
}

1.2 创建精灵帧的简单方法

  • 从纹理帧创建AnimatedSprite的简单方法

PIXI.AnimatedSprite.fromFrames (frames)

Name Type Description
frames string[] AnimatedSprite将使用的帧数组id作为它的纹理帧。
  • 从图片创建AnimatedSprite的简单方法

PIXI.AnimatedSprite.fromImages (images)

Name Type Description
images string[] AnimatedSprite将使用的图像url数组作为它的纹理帧

2.常用方法

2.1 play()

动画精灵开始运动(图片开始循环)

 animatedSprte.play()

2.2 stop ()

动画精灵停止运动,停止在第一帧

 animatedSprte.stop ()

2.3 update()

我不太清楚这个update是怎么用的,下面是官方的介绍,我没看懂。

Updates the object transform for rendering.

Name Type Description
deltaTime number Time since last tick.

控制动画精灵帧切换速度可以用 animatedSprte.animationSpeed = 0.1 数字越小越慢

2.4 gotoAndPlay()

gotoAndPlay(frameNumber) void

转到一个特定的帧并开始播放AnimatedSprite。

Name Type Description
frameNumber number 起始帧索引.

2.5 gotoAndStop ()

gotoAndStop (frameNumber) void

停止AnimatedSprite并进入特定帧。

Name Type Description
frameNumber number 帧索引停止在哪帧

2.6 destroy ()

停止AnimatedSprite并销毁它。

2.7 小demo(部分代码)

// 简单方法创建动画精灵
let ss = new PIXI.AnimatedSprite.fromImages(['./images/down1.png', './images/down2.png', './images/down3.png', './images/down4.png'])
//添加到舞台
app.stage.addChild(ss)
//设置精灵位置
ss.y = 220
ss.animationSpeed = 0.1
// ss.play()
//从第一张图片开始
ss.gotoAndPlay(0)
//停在第二张图片
ss.gotoAndStop(1)
//销毁
ss.destroy()

猜你喜欢

转载自blog.csdn.net/qq_61672548/article/details/127289093