前面三章已经讲述了如何显示精灵与对精灵的操作,本次讲述的是用pixi.js绘制各种图形,以及两个精灵之间的碰撞检测。
图形绘制
Pixi也有自己的底层绘制工具,可以使用这些绘制工具制作矩形,形状,线,复杂的多边形和文本等Pixi的底层绘制工具使用了与 Canvas绘画API几乎相同的API,与Canvas不同的是,Pixi通过WebGL在GPU上高性能的渲染和绘制形状- 所有形状的绘制,都先从创建
Pixi的Graphics类实例开始
const rectangle = new PIXI.Graphics();
矩形/圆角矩形
- 使用
drawRect方法绘制矩形 - 绘制一个
x坐标170,y坐标170,64x64像素大小,带红色边框的蓝色矩形
rectangle.beginFill(0x66ccff); // 设置填充颜色
rectangle.lineStyle(4, 0xff3300, 1); // 设置外边框
rectangle.drawRect(100, 100, 100, 100); // x坐标为100,y坐标为100,宽高为100
rectangle.endFill(); // 结束绘制
this.app.stage.addChild(rectangle); // 将矩形添加都舞台
- 使用
drawRoundedRect方法绘制圆角矩形 - 它有5个参数分别为
x、y左上角坐标、width、height宽高、cornerRadius圆角大小
const roundRect = new PIXI.Graphics();
roundRect.beginFill(0xff9933);
roundRect.lineStyle(5, 0x99ccff, 0.8);
roundRect.drawRoundedRect(200, 10, 70, 80);
roundRect.endFill();
this.app.stage.addChild(roundRect);
圆形/椭圆
- 使用
drawCircle方法绘制圆形,它有3个参数分别是x、y(圆心)、半径radius
const circle = new PIXI.Graphics();
circle.beginFill(0x996ff); // 设置填充色
circle.drawCircle(50, 50, 20); // 圆心点为(50,50),半径为20
circle.endFill(); // 结束绘制
this.app.stage.addChild(circle);
-
使用
drawEllipse方法来绘制椭圆,它有四个参数分别是x、y(椭圆左上角)、width、height(宽高)- 椭圆左上角: 假设椭圆被透明的矩形边界框包围,该框的左上角将代表椭圆的
x、y锚点位置 - 若椭圆宽高相等,则为圆形
- 椭圆左上角: 假设椭圆被透明的矩形边界框包围,该框的左上角将代表椭圆的
const ellipse = new PIXI.Graphics();
ellipse.beginFill(0xffff00);
ellipse.drawEllipse(200, 300, 100, 50);
ellipse.endFill();
this.app.stage.addChild(ellipse);
线条/多边形
- 使用
lineStyle方法定义线的样式,使用moveTo和lineTo方法绘制线的起点和终点 - 绘制一个10像素宽的线条
const line = new PIXI.Graphics();
line.lineStyle(10, 0xffffff, 1);
line.moveTo(300, 0); // 起始坐标
line.lineTo(600, 200); // 终点坐标
line.position.set(0, 0);
this.app.stage.addChild(line);
- 使用
drawPolygon方法将线连接在一起,并用颜色进行填充,以制作复杂的形状 - 它的参数是由位置
x、y点确定一个位置组成的路径数组 - 绘制一个绿色边框的三角形,默认绘制点为
(400,400)
const triangle = new PIXI.Graphics();
triangle.beginFill(0x66ff33);
triangle.lineStyle(5, 0xcd0000, 0.7);
triangle.drawPolygon([300, 200, 500, 200, 400, 400]); // 坐标(300,200)、(500,200)、(400,400)
triangle.endFill();
this.app.stage.addChild(triangle);
显示文字
- 使用
PIXI.Text对象在舞台上显示文字,Pixi的Text对象继承自Sprite类,因此Text包含精灵类的全部属性,可以在舞台上调整文本的位置和大小 Pixi通过使用Canvas绘图API将文本呈现到一个不可见的临时canvas元素来生成文本对象,然后将canvas转换为WebGL纹理
const text = new PIXI.Text("javaScript");
text.position.set(200, 500);
this.app.stage.addChild(text);
- 若想定义文本的样式,使用
Pixi的TextStyle类对文本样式初始化
const textStyle = new PIXI.TextStyle({
fontFamily: "Arial", // 字体样式
fontSize: 36, // 字号
fill: "pink", // 填充颜色
stroke: "#ff3300", // 线条颜色
strokeThickness: 4, // 线条宽度
dropShadow: true, // 是否有阴影
dropShadowColor: "#ffffff", // 阴影颜色
dropShadowBlur: 4, // 阴影模糊程度
dropShadowAngle: Math.PI / 6, // 阴影角度
dropShadowDistance: 6, // 阴影距离
});
const text = new PIXI.Text("javaScript", textStyle);
- 后续想更改文本内容,使用
text属性更改
myText.text = "typeScript";
- 可以使用
style属性重新定义样式
myText.style.fill = "purple"; // 修改原有单个属性
myText.style = { fill: "purple" }; // 覆盖所有属性
-
可以对超长字符串换行
breakWords: 设置为true,英文单词是否能打断wordWrap: 设置为truewordWrapWidth: 最大宽度像素值align: 设置多行文本的对齐方式(单行不生效)
myText.style.breakWords = true;
myText.style.wordWrap = true;
myText.style.wordWrapWidth = 100;
myText.style.align = "center";
碰撞检测
- 可以使用一个名为
hitTestRectangle的自定义函数,该函数检查是否有两个矩形的Pixi精灵正在接触 - 如果两个精灵重叠,函数将返回
true
hitTestRectangle(sprite1, sprite2)
- 实现: 如果猫碰到了盒子,盒子就会变成红色,文本对象就会显示
Hit! - 判断原理:猫精灵与矩形中心点之间的距离,小于猫精灵与矩形的半宽和,则为碰撞
// 碰撞检测函数
hitTestRectangle(moveSprite, otherSprite) {
const { rectangle } = otherSprite;
// 定义所需变量
let hit = false; // 是否碰撞
// 寻找每个精灵的中心点
moveSprite.centerX = moveSprite.x + moveSprite.width / 2; // 移动精灵水平中心点
moveSprite.centerY = moveSprite.y + moveSprite.height / 2; // 移动精灵垂直中心点
rectangle.centerX = rectangle.x + rectangle.width / 2; // 矩形水平中心点
rectangle.centerY = rectangle.y + rectangle.height / 2; // 矩形垂直中心点
// 找出每个精灵的半高和半宽
moveSprite.halfWidth = moveSprite.width / 2; // 移动精灵半宽
moveSprite.halfHeight = moveSprite.height / 2; // 移动精灵半高
rectangle.halfWidth = rectangle.width / 2; // 矩形半宽
rectangle.halfHeight = rectangle.height / 2; // 矩形半高
// 移动精灵和矩形之间的距离
const gapX = moveSprite.centerX - rectangle.centerX;
const gapY = moveSprite.centerY - rectangle.centerY;
// 算出移动精灵和矩形半宽半高的总和
const combineWidth = moveSprite.halfWidth + rectangle.halfWidth;
const combineHeight = moveSprite.halfHeight + rectangle.halfHeight;
// 检查x轴上是否有碰撞
// 判断两个精灵中心点间的距离,是否小于精灵半宽和
if (Math.abs(gapX) < combineWidth) {
// 检查y轴是否有碰撞
hit = Math.abs(gapY) < combineHeight;
} else {
hit = false;
}
return hit;
}
- 运行游戏
playGame(moveSprite, otherSprite) {
moveSprite.x += moveSprite.vx;
moveSprite.y += moveSprite.vy;
// 碰撞检测
const isHit = this.hitTestRectangle(moveSprite, otherSprite);
if (isHit) {
otherSprite.message.text = "hit!";
otherSprite.rectangle.tint = 0xff3300;
} else {
otherSprite.message.text = "No Collision...";
otherSprite.rectangle.tint = 0x66ccff;
}
},