PixiJS 的画格子使用优化
pixijs
是一个开源的 canvas 库,我们可以用这个库来做很多的事情,下面我们要做一个画格子的游戏。
Graphics简单使用
官网上对 graphics 介绍很多,这边不涉及到高级用法,graphics
就是我们用来画格子的。
下面上代码:
const baseWidth = 500
// 声明一个应用
let app = new PIXI.Application({ width: baseWidth, height: baseWidth });
// 声明 graphics,开始画一个5*5的白色矩形
const graphics = new PIXI.Graphics();
graphics.beginFill(0xffffff);
graphics.drawRect(0,0,5,5);
// 添加应用到 dom 中去
app.stage.addChild(graphics);
document.body.appendChild(app.view);
一个哪里够,我要打十个(吹牛的)但是一个格子确实不够,我要画1000个,不对,我要画1000000个
// 格子数
const gridSize = 1000
// gridCount 表示每个格子的宽度,baseWidth表示一个 500 像素大小的 dom
const gridCount = baseWidth / gridSize
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
graphics.beginFill(0xffffff);
graphics.drawRect(x * gridCount, y * gridCount, gridCount, gridCount);
}
}
颜色就让随机吧
// 生成随机颜色的函数
function getRandomColor() {
const letters = "0123456789ABCDEF";
color = "";
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
完整代码:
const baseWidth = 500;
// 格子大小
const gridSize = 1000;
// 每一个格子的大小
const gridCount = baseWidth / gridSize;
let app = new PIXI.Application({ width: baseWidth, height: baseWidth });
const graphics = new PIXI.Graphics();
app.stage.addChild(graphics);
document.body.appendChild(app.view);
draw();
// 生成随机颜色的函数
function getRandomColor() {
const letters = "0123456789ABCDEF";
color = "";
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
// 画点
function draw() {
console.time("draw");
// 画格子
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
graphics.beginFill("0x" + getRandomColor());
graphics.drawRect(x * gridCount, y * gridCount, gridCount, gridCount);
}
}
console.timeEnd("draw");
// 渲染
console.time("render");
app.render();
console.timeEnd("render");
app.stop();
}
最后画的格子大概长这个样子:
书写一个按钮,每次点击就重新画一次吧
<button onclick="draw()">画画</button>
渲染卡顿
画完格子了但是卡顿的很,看了一下渲染时间
渲染时间很长?
卡顿原因
研究了一下,每一次使用 graphics 画格子都是递增的,比如在坐标(5,5)画一个绿色格子,然后再在坐标上(5,5)画一个红色格子,并不是修改颜色,而是往上覆盖格子,如图
解决方案
看了官网,没有修改的方法,但是可以通过修改geometry
的值来实现。但是每次修改都要使用geometry.invalidate()
修正一下数据。尝试了一下,这个方式还是渲染很慢,只是保证了数据不递增而已。当格子数很多的时候,还是会卡顿。
使用精灵
这个问题困扰了很久(救命
大佬出现了,他告诉我可以使用精灵,并且通过纹理来实现,并不是要一定画上去
上代码:
const buffer = new Uint8Array(gridSize * gridSize * 4);
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
const offset = (y + gridSize * x) * 4;
const color = hexToRGBA(getRandomColor());
buffer[offset + 0] = color[0]; // R value
buffer[offset + 1] = color[1]; // G value
buffer[offset + 2] = color[2]; // B value
buffer[offset + 3] = 255; // A value
}
}
const texture = PIXI.Texture.fromBuffer(buffer, gridSize, gridSize);
const sprite = new PIXI.Sprite(texture);
sprite.x = 0;
sprite.y = 0;
sprite.width = baseWidth;
sprite.height = baseWidth;
app.stage.removeChildren();
app.stage.addChild(sprite);
补充方法,将16进制转换为rgba
function hexToRGBA(hex, alpha = 1) {
let r = parseInt(hex.slice(1, 3), 16),
g = parseInt(hex.slice(3, 5), 16),
b = parseInt(hex.slice(5, 7), 16);
return [r, g, b, alpha];
}
具体完整的代码:
const baseWidth = 500;
// 格子大小
const gridSize = 1000;
// 每一个格子的大小
const gridCount = baseWidth / gridSize;
let app = new PIXI.Application({ width: baseWidth, height: baseWidth });
document.body.appendChild(app.view);
draw();
// 生成随机颜色的函数
function getRandomColor() {
const letters = "0123456789ABCDEF";
color = "#";
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function hexToRGBA(hex, alpha = 1) {
let r = parseInt(hex.slice(1, 3), 16),
g = parseInt(hex.slice(3, 5), 16),
b = parseInt(hex.slice(5, 7), 16);
return [r, g, b, alpha];
}
// 画点
function draw() {
console.time("draw");
// 画格子
const buffer = new Uint8Array(gridSize * gridSize * 4);
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
const offset = (y + gridSize * x) * 4;
const color = hexToRGBA(getRandomColor());
buffer[offset + 0] = color[0]; // R value
buffer[offset + 1] = color[1]; // G value
buffer[offset + 2] = color[2]; // B value
buffer[offset + 3] = 255; // A value
}
}
const texture = PIXI.Texture.fromBuffer(buffer, gridSize, gridSize);
const sprite = new PIXI.Sprite(texture);
sprite.x = 0;
sprite.y = 0;
sprite.width = baseWidth;
sprite.height = baseWidth;
app.stage.removeChildren();
app.stage.addChild(sprite);
console.timeEnd("draw");
// 渲染
console.time("render");
app.render();
console.timeEnd("render");
app.stop();
}
渲染时间
这样时间就短了很多了!
转载自:https://juejin.cn/post/7336750909508222988