PixiJS 的画格子使用优化

pixijs 是一个开源的 canvas 库,我们可以用这个库来做很多的事情,下面我们要做一个画格子的游戏。

Graphics简单使用

官网上对 graphics 介绍很多,这边不涉及到高级用法,graphics 就是我们用来画格子的。

下面上代码:

javascript 复制代码
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个

javascript 复制代码
// 格子数
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);
    }
 }

颜色就让随机吧

javascript 复制代码
// 生成随机颜色的函数
function getRandomColor() {
   const letters = "0123456789ABCDEF";
   color = "";
   for (let i = 0; i < 6; i++) {
     color += letters[Math.floor(Math.random() * 16)];
   }
   return color;
 }

完整代码:

javascript 复制代码
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();
}

最后画的格子大概长这个样子:

书写一个按钮,每次点击就重新画一次吧

ini 复制代码
<button onclick="draw()">画画</button>

渲染卡顿

画完格子了但是卡顿的很,看了一下渲染时间

渲染时间很长?

卡顿原因

研究了一下,每一次使用 graphics 画格子都是递增的,比如在坐标(5,5)画一个绿色格子,然后再在坐标上(5,5)画一个红色格子,并不是修改颜色,而是往上覆盖格子,如图

解决方案

看了官网,没有修改的方法,但是可以通过修改geometry的值来实现。但是每次修改都要使用geometry.invalidate()修正一下数据。尝试了一下,这个方式还是渲染很慢,只是保证了数据不递增而已。当格子数很多的时候,还是会卡顿。

使用精灵

这个问题困扰了很久(救命

大佬出现了,他告诉我可以使用精灵,并且通过纹理来实现,并不是要一定画上去

上代码:

javascript 复制代码
    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

javascript 复制代码
    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];
    }

具体完整的代码:

javascript 复制代码
     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();
    }

渲染时间

这样时间就短了很多了!

相关推荐
Zhencode11 分钟前
Vue3 响应式依赖收集与更新之effect
前端·vue.js
x-cmd16 分钟前
[x-cmd] jsoup 1.22.1 版本发布,引入 re2j 引擎,让 HTML 解析更安全高效
前端·安全·html·x-cmd·jsoup
天下代码客33 分钟前
使用electronc框架调用dll动态链接库流程和避坑
前端·javascript·vue.js·electron·node.js
weixin199701080161 小时前
【性能提升300%】仿1688首页的Webpack优化全记录
前端·webpack·node.js
冰暮流星1 小时前
javascript之数组
java·前端·javascript
晚霞的不甘2 小时前
Flutter for OpenHarmony天气卡片应用:用枚举与动画打造沉浸式多城市天气浏览体验
前端·flutter·云原生·前端框架
xkxnq2 小时前
第五阶段:Vue3核心深度深挖(第74天)(Vue3计算属性进阶)
前端·javascript·vue.js
三小河2 小时前
Agent Skill与Rules的区别——以Cursor为例
前端·javascript·后端
Hilaku2 小时前
不要在简历上写精通 Vue3?来自面试官的真实劝退
前端·javascript·vue.js
三小河2 小时前
前端视角详解 Agent Skill
前端·javascript·后端