曾几何时,在网络上创建丰富的交互式图形体验只能通过现已不复存在的Adobe Flash播放器插件来实现。但是,WebGL的出现改变了这个游戏。它带来了一个在网络上丰富的可视化时代。
WebGL是一个JavaScript渲染API,提供高性能的2D和3D互动图形能力和GPU加速。与其前身不同,该API可以在任何兼容的网络浏览器中工作,无需插件。然而,WebGL有一个更陡峭的学习曲线,所以有几个框架已经建立在该API之上,以减轻直接使用它的复杂性。
下面是一些基于WebGL的最流行的框架。
在这篇文章中,我们将回顾你需要知道的一切,以开始使用PixiJS,一个超级快速的WebGL框架,用于渲染2D图形,与React。本文的演示部分将包括几个PixiJS动画实例。
跳到前面。
前提条件
要继续学习本教程,你应该具备以下条件。
- 关于React及其概念的基础知识
- 对PixiJS(通常被称为PIXI)的基本了解
在React中实现PixiJS
PixiJS的设计是为了与HTML5一起工作,开箱即用。在React这样的库中实现它需要一个辅助库,如ReactPixi,它将促进PixiJS应用程序的集成和渲染。
ReactPixi是一个开源库,用于在React中渲染高性能的PixiJS应用程序。该库提供了有用的组件,使用React的声明式风格,使编写PixiJS应用程序更加容易和快速。
让我们通过一个例子来看看如何在React中实现和渲染一个PixiJS应用程序。
设置一个React项目
作为第一步,我们需要设置一个React项目样本并安装所需的软件包。
让我们在终端运行以下命令,用create-react-app引导一个React应用。
npx create-react-app pixi-react-app
create-react-app将在pixi-react-app 文件夹中安装最新版本的React。然而,在撰写本文时,ReactPixi并不支持React v18。因此,在我们的项目中使用该库之前,我们需要将React降级到17版。
要做到这一点,首先,打开项目根目录下的package.json 文件,替换以下几行代码。
"react": "^18.0.0"
"react-dom": "^18.0.0"
用这个片段。
"react": "^17.0.2"
"react-dom": "^17.0.2"
接下来,转到index.js 文件并替换以下代码。
import ReactDOM from 'react-dom/client'
用这个命令。
import ReactDOM from 'react-dom';
另外,替换下面的代码。
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
用这个片段。
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
最后,删除项目根目录下的node_modules 文件夹并运行。
npm install
运行上述命令后,你的React项目将被降级到v17。现在你可以继续安装PixiJS和ReactPixi。
npm install pixi.js @inlet/react-pixi
创建一个PixiJS画布
设置好项目后,清理一下模板代码和文件。接下来,打开App.js 文件,并从ReactPixi导入Stage 组件。
import Stage from "@inlet/react-pixi"
PIXI并不直接向DOM渲染对象。相反,它有一个渲染器,可以生成一个HTML5画布,作为浏览器中精灵和纹理等对象的显示区域。我们刚刚导入的Stage 组件包含了创建PIXI渲染器的基础代码。
该组件也是一个根容器对象,在PIXI中称为Stage 。这个Stage 对象是一个根容器,它容纳了我们希望PIXI显示给渲染器的所有对象。
你可以像这样把Stage 组件添加到App.js 组件中。
const App = () => {
return(
<Stage>
</Stage>
)}
现在,通过在终端内运行npm start ,启动开发服务器。你应该在浏览器中看到一个长方形的画布元素,类似于下面的图片。

呈现的黑色方块是PIXI将显示对象的显示区域。
Stage 组件接受可用于配置画布的属性。例如,width 和height 道具的设置是为了确定画布的尺寸。
const App = () => {
return(
<Stage width={300} height={300}>
</Stage>
)}
我们还可以使用options 道具来设置更多的属性,如抗锯齿(antialias),autoDensity ,和backgroundColor ,到Stage 组件。
const App = () => {
return(
<Stage
width={300}
height={300}
options={{
backgroundColor: 0x012b30,
antialias: true
}}>
</Stage>
)}
现在,让我们来看看我们如何将物体渲染到画布上。
渲染精灵
Sprites是PixiJS的构建块。这些特殊的图像可以用代码进行操作和控制。在属性的帮助下,精灵对于制作交互式和动画式的图形非常有用,这些属性可以让我们控制它们的位置、大小和一系列其他功能。
用ReactPixi渲染精灵是相当直接的。该库提供了一个Sprite 组件,可用于向浏览器加载和渲染图像。这个组件避免了在加载到渲染器之前将精灵图像转换为WebGL纹理的复杂问题。
要使用Sprite 组件,请像这样在App.js 文件中导入它。
import { Stage, Sprite} from '@inlet/react-pixi'
Sprite 组件提供了几个有用的属性,可以用来操作和控制精灵图像的外观和位置。一个例子是image 属性,它接受要渲染到画布上的图像的相对或绝对URL。
向画布加载精灵就像在Stage JSX标签内嵌套Sprite 组件一样简单,并将指向图像源的URL传递给image 道具。
...
import wizard from "./wizard.png";
const App = () => {
return(
<Stage ...>
<Sprite image={wizard} />
</Stage>
)}
在你加载图像并保存你的项目后,你应该在浏览器中看到Sprite 图像在画布中呈现。
![]()
感谢LuizMelo将这个精灵免费提供给我们使用。
Sprite 组件的一些可选的道具包括width 和height 道具以及x 和y 道具。width 和height 属性用于操纵精灵的尺寸,而x 和y 属性则用于定位精灵。x 道具将精灵定位在X轴上,而y 道具将其定位在Y轴上。
<Sprite image={wizard} x={150} y={150}/>
渲染图形
我们可以用ReactPixi做更多事情,而不仅仅是向渲染器加载图像。该库提供了一个Graphics 组件,利用PIXI的低级绘图工具,使我们能够绘制不同种类的形状和线条,还可以向渲染器添加纹理。
让我们使用Graphics 组件来为渲染器绘制一个矩形图形。
首先,从ReactPixi导入Graphics 组件,并将其嵌套在Stage 标签中。
import { Stage, Sprite, Graphics} from '@inlet/react-pixi'
接下来,用下面的代码创建一个函数,并把它作为一个值传到Graphics draw 这个道具里面。
const App = () => {
const draw = g => {
g.beginFill(0x0033cc, 1)
g.drawRect(250, 150, 150, 120)
g.endFill()
};
return(
<Stage ...>
<Sprite image={wizard} />
<Graphics draw={draw}/>
</Stage>
)}
在draw函数里面,我们将用beginFill 方法设置形状的填充颜色,然后用drawRect 方法绘制形状。drawRect'的参数分别是x ,y ,height ,和width 属性。
在你保存项目后,一个蓝色的方框应该出现在我们之前加载的画布内的Sprite 图片旁边。
![]()
我们可以通过在draw 函数内添加一个lineStyle 方法并赋予它以下属性来给这个形状一个轮廓。
const draw = g => {
...
g.lineStyle(4,0xff0000,1)
g.endFill()
};

draw 道具是一个回调函数,每次其属性发生变化时都会被调用。所以一定要通过在React的useCallback 钩子里面声明draw 函数来记忆它。
const draw = useCallback(g => {
g.beginFill(0x0033cc, 1)
g.lineStyle(4,0xff0000,1)
g.drawRect(250, 150, 150, 120)
g.endFill()
},[]);
渲染文本
ReactPixi的Text 组件利用PIXI的Text 对象来向渲染器显示文本。该组件有两个主要道具。text一个是接受要显示的文本,另一个是style ,它接受一个定义文本属性的对象。
<Text
text="Hello World"
style={
new TextStyle({
align: 'center',
fill: ['#ffffff', '#00ff99'], // gradient
stroke: '#01d27e',
strokeThickness: 5,
letterSpacing: 20,
/>
要在你的项目中使用Text 组件,首先从ReactPixi导入它。
import { Stage, Sprite, Graphics, Text } from '@inlet/react-pixi';
接下来,把它添加到Stage ,并传递给它一些textStyle 的道具。
const textStyle = new TextStyle({
align: "center",
fontWeight: "bold",
fill: ["#26f7a3", "#01d27e"],
stroke: "#eef1f5",
strokeThickness: 1,
letterSpacing: 5,
wordWrap: false,
wordWrapWidth: 350
})
const App = () => (
<Stage ...>
….
<Text text="Hello Logrocketer" style={textStyle}/>
….
</Stage>
);
保存项目后,我们看到文本 "Hello Logrocketer "被渲染到画布上。

添加过滤器
ReactPixi提供了一个withFilters 函数,简化了向渲染器中的对象添加过滤器的过程。该函数使用PIXI的全局对象来访问过滤器对象及其属性。
为了给我们的精灵添加过滤器,我们必须首先从PixiJS中导入withFilters 函数和PIXI 全局对象,像这样。
import { Stage, Sprite, Graphics, Text, withFilter } from '@inlet/react-pixi';
import * as PIXI from 'pixi.js';
withFilters 函数接受两个参数,一个容器组件和一个对象配置。
const Filters = withFilters(Container, {
blur: PIXI.filters.BlurFilter
});
Container 参数给了withFilters 函数一个容器对象的特性。
如前所述,容器是一个对象,用于将其他要在渲染器中显示的对象分组。我们在Container 上设置的过滤器将被应用于嵌套在容器中的对象。
第二个参数是过滤器配置,包含过滤器的偏好。这就是我们从PIXI 全局对象中访问filter 对象,并设置我们想要应用于容器的过滤器的种类。在本例中,我们使用BlurFilter 对象的属性来应用一个blur 过滤器。
不要忘记像这样从ReactPixi导入Container 组件。
import { Stage, Sprite, Graphics, Text, withFilter, Container } from '@inlet/react-pixi';
现在我们已经配置了一个过滤器容器,让我们把它应用到我们的Sprite 。将Filters 容器添加到Stage ,并将Sprite 组件嵌套其中。然后,将一个blur 的道具传递给容器,并赋予它以下属性。
const App = () => (
<Stage>
….
<Filters blur={{ blur: 5 }} >
<Sprite image={wizard} .../>
</Filters>
….
</Stage>
);
这将在渲染器中为精灵添加一个模糊的过滤效果。你可以通过改变blur 这个道具的值来调整模糊效果。

动画精灵
在PIXI中,需要一个循环器,也被称为游戏循环器,以使物体产生动画。gameLoop 函数每秒钟被调用60次,嵌套在该函数内的每段代码也被同样频繁地调用。
例如,下面的代码将使巫师精灵以每帧1像素的速度向左移动。
function setup() {
app.ticker.add((delta) => gameLoop(delta));
}
function gameLoop(delta) {
wizard.x -= 1;
}
循环函数是使用PIXI的ticker事件创建的;它相当于JavaScript的requestAnimationFrame 方法。ReactPixi提供了一个useTick Hook,它将一个监听器绑定到ticker事件上。通过它,我们可以对Sprite 的位置和状态进行动画处理。
在我们开始制作动画之前,我们首先要从ReactPixi和React中分别导入useTick 和useState Hooks。
import { useTick, ... } from '@inlet/react-pixi';
import {..., useState} from 'react'
接下来,让我们为向导Sprite 创建一个新的组件,并将其嵌套在App.js 组件的容器中。
...
const Wizard = () =>{
return(
<Sprite
image={wizard}
x={x}
y={y}
anchor={0.5}
scale={1.3}
/>
)
}
const App = () => (
<Stage ...>
<Wizard />
….
</Stage>
);
现在。在Sprite 组件的函数内添加以下代码。
import { Stage, Container, Sprite, Text, Graphics, withFilters,useTick } from '@inlet/react-pixi'
import { useState, useCallback} from "react";
import * as PIXI from "pixi.js"
import wizard from "./wizard.png";
let i = 0;
const Wizard = () =>{
const [x, setX] = useState(0)
const [y, setY] = useState(0)
useTick(delta =>{
i += 0.05 * delta;
setX(Math.sin(i) * 100)
setY(Math.sin(i/1.5) * 100)
});
return(
<Sprite
image={wizard}
x={x}
y={y}
anchor={0.5}
scale={1.3}
/>
)
}
const App = () => (
<Stage ...>
<Wizard />
….
</Stage>
);
在上面的代码块中,我们声明一个变量,i ,并给它赋值为0 。接下来,我们使用useState Hook创建两个状态变量,x 和y ,其初始值为0 。然后,我们调用useTick Hook并传递给它一个回调函数。
在回调函数中,我们给i 变量分配一个delta 的值,并将该变量的值乘以100的正弦结果设置为x 和y 状态变量。
最后,我们将x 和y 状态变量的值分别传递给Sprite'的x 和y 道具。
保存代码后,你的精灵的动画效果应该类似于下面显示的向导。
![]()
结语
在本文中,我们演示了如何创建一个PIXI画布,将精灵、文本和图形对象加载到渲染器中,为对象添加过滤器,以及为对象制作动画。
本文的目的是让你了解如何在React中实现PixiJS应用程序。