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

渲染时间

这样时间就短了很多了!

相关推荐
陆枫Larry12 小时前
从一个按钮间距,聊透 CSS 的 gap 属性
前端
北冥有鱼12 小时前
mqtt 测试
前端·后端
张鑫旭13 小时前
都AI时代了,我为何还在学习前端基础知识?
前端
swipe13 小时前
正则表达式入门到进阶:从表单校验到手写模板引擎
前端·javascript·面试
阿祖zu13 小时前
别再优化 RAG 了,适配 Agent 的 LLM Wiki 知识库理念
前端·后端·aigc
kyriewen13 小时前
前端错误监控最全指南:捕获 JS 异常、Promise 拒绝、资源加载失败,附上报代码
前端·javascript·监控
狗哥哥13 小时前
船队运营可视化技术方案
前端
大家的林语冰14 小时前
ESLint 近期动态大全,新版本正式发布,antfu 大佬推荐的插件也更新了!
前端·javascript·前端工程化
只会cv的前端攻城狮14 小时前
DSL 领域模型架构设计:消灭 CRUD 重复工作
前端·架构
码事漫谈14 小时前
时序数据库2026盘点:国产数据库如何以“融合多模”走出差异化之路?
前端·后端