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

渲染时间

这样时间就短了很多了!

相关推荐
东方小月8 小时前
从零开发一个 Coding Agent(四):使用状态机校验大模型事件流
前端·人工智能·后端
Csvn9 小时前
🧩 ESM vs CJS 混用的 7 个「天坑」——从 TypeScript 编译到 Node 与浏览器
前端
Csvn9 小时前
🎯 Web 性能 API 集合:Performance Observer 的 5 个冷门妙用
前端
Csvn9 小时前
深入 React 闭包陷阱:从根源上理解并根治 stale closure
前端
whyfail9 小时前
前端学 Spring Boot(8):接口为什么越用越慢?
前端·spring boot·后端
用户0595401744610 小时前
LangChain 记忆测试踩坑实录:这两个坑让我排查了 4 小时
前端·css
程序员黑豆10 小时前
鸿蒙应用开发:@Monitor 装饰器使用教程
前端·harmonyos
用户9385156350710 小时前
从零构建《天龙八部》知识库:EPUB 加载→文本分割→向量嵌入→Milvus 存储→RAG 问答,一条链路打通
javascript·人工智能·全栈
SamChan9011 小时前
在Web应用中集成PDF多语言翻译功能:PDFTranslator API实战指南
前端·python·ai·pdf·yapi·机器翻译
kyriewen11 小时前
AI Agent 9秒删光了生产数据库——我给自己的项目做了5个紧急检查
前端·ai编程·claude