思索 p5.js 的最佳实践

本文写于 2020 年 12 月 18 日

p5.js 是一个 JavaScript 库,用于为艺术家、设计师提供更容易上手的创意编程。

它有着完整的一套基于 Canvas 的作画功能,并且你可以把整个浏览器都当成你的“画布”——利用 p5.dom.js 可以很方便地与其他 HTML 元素进行交互;利用 p5.sound.js 可以很简单的对声音进行分析与处理。

官网推荐用法

在官网的例子中,推荐使用 <script> 标签引入的方法:

<html>
  <head>
    <!-- ...... -->
    <script src="path/to/your/p5.js"></script>
  </head>
  <body>
    <script>
      function setup() {
        createCanvas(300, 500);
      }

      function draw() {}
    </script>
  </body>
</html>

这样是让所有的变量、函数都暴露在全局之下,所以我们可以直接使用 setup, draw 函数进行操作。

但这对于新手来说,这样的做法存在一个致命问题:没有代码提示。并且也不符合我们现代 Web 开发的习惯——模块化

在动画复杂的情况下,代码会越来越多、越来越邋遢,直到成为一座“屎山”!!!

所以这让我不由得思考起了 p5.js 的最佳实践究竟该如何。

关于最佳实践的思考

p5.js 拥有多个生命周期函数:

  • 用于预加载数据的 preload 函数;

  • 在最开始执行,并且只执行一次的 setup 函数;

  • 一秒执行大概 20 多次的 draw 函数;

  • 鼠标左键点击时触发的 mousePressed 函数;

  • ……

p5 画图的根本其实就是在不同生命周期里对数据进行操作,然后将数据具体转化为图像

所以按照 MVC 的思想:view = render(data),我们应该拒绝在这些钩子函数中「直接」操作数据——将动画抽象成为独立的 Service(服务),操作数据交给 Service 自己的方法,我们只需要在 draw 函数中对 Service 内的数据进行绘制即可。

这样讲可能大家还不太明白,那么 talk is cheap, show me the code 吧!

运用 OOP 与 SOA 解耦项目

接下来我们通过一个例子看看如何对项目进行解耦。

要求:了解面向对象的编程。

目标:制作一个漫天繁星。

step1 创建 Star 类

第一步我们需要一个 Star 类。

class 星星 {
  x坐标 = 0;
  y坐标 = 0;

  透明度 = 0;

  随机放置星星() {
    // 随机 x y 坐标值
  }

  闪烁() {
    // 操作透明度
  }
}

step2 创建 Service

然后再为所有的星星闪烁制作一个服务,这个服务用来管理所有的星星(服务其实就是一个 class)。

class 星星服务 {
  星星们 = [];

  get 星星的位置() {
    this.星星们.处理一下((星星) => {
      返回 {
        x: 星星的x坐标,
        y: y坐标,
        opacity: 透明度,
      }
    })
  }

  创建星星们() {
    重复 100 次:this.星星们.增加(new 星星());
  }
}

step3 写入 p5

let 星星服务实例;

function preload() {
  星星服务实例 = new 星星服务class();
}

function setup() {
  星星服务实例.创建星星们();
}

function draw() {
  background(0);
  if (星星服务实例.星星们 的 长度 > 0) {
    星星服务实例.星星的位置.遍历((星星) => {
      fill(255, 星星.透明度);
      ellipse(星星.x, 星星.y, 半径, 半径);
    })
  }
}

目前动画比较简单,还看不出来该方案有什么优势。但是一旦动画更加复杂,该方案对原来写法的解耦的优越性将会是毋庸置疑的。

我们仅仅需要的是在不同的生命周期函数中调用服务的方法,然后在 draw 函数中拿到数据后进行绘图!

ts-p5 以及环境搭建

我封装了一个库,可以提供比较好的 p5 代码补全:https://github.com/AerospaceXu/ts-p5

考虑到使用 p5 的初学者较多,还是说一下如何搭建一个前端项目吧。

完整版本会写在最后一节,这里只提供可运行的步骤。

  1. 官网下载 Node.js,一路默认选项安装;

  2. 下载 VSCode,他为我们提供了完善的代码提示支持;

  3. 新建项目文件夹,命名;

  4. 将文件夹拖入 VSCode;

  5. 点击 VSCode 菜单栏的“终端”或是“Terminal”选项,选择新建终端;

  6. 终端内输入:npm config set registry https://registry.npm.taobao.org && npm init -y && npm i ts-p5 && npm i -D parcel-bundler

  7. 此时文件夹内出现了 package.jsonpackage-lock.json 文件,打开前者;

  8. 在第一行大括号的末尾回车,输入:

    { // 在这里回车
      "scripts": {
        "start": "./node_modules/.bin/parcel ./src/index.html --no-cache",
        "build": "./node_modules/.bin/parcel build ./src/index.html --no-cache -d build"
      },
      // ......
  9. 新建 src 文件夹,让你的目录看起来是这样:

    - 你的文件夹名称
       - node_modules
       - package.json
       - package-lock.json
       - src
         - index.html
         - style.css
         - main.js
  10. 只需要在 index.html 中引入 main.js 和 style.css;

  11. 在 index.html 中写入以下代码:

    <body>
      <div id="sketch"></div>
    
      <script src="./main.js"></script>
    </body>
  12. 在 main.js 中写入以下代码:

    import { sketchCreator } from 'ts-p5';
    import { getWindowSize } from 'ts-p5/utils';
    
    sketchCreator(
      {
        preload: function () {},
        setup: function (p) {
          const { width, height } = getWindowSize();
          p.createCanvas(width, height);
          p.background(0);
        },
        draw: function (p) {
          p.background(0);
          p.noStroke();
        },
        mousePressed: function (p) {
          console.log(p.mouseX);
          console.log(p.mouseY);
        },
      },
      document.querySelector('#sketch')
    );

然后在终端输入 npm run start,待显示

Server running at http://localhost:1234
✨  Built in xxxx.

之后,方可打开浏览器输入刚刚输出的网址。

观察到一片漆黑,就完成了。

之后如果需要使用到 p5 的函数或者是变量,输入 p. 就会自动弹出代码提示了(不要忘记在函数参数传入 p 哦)。

为代码添加提示完整版(初学者向)

为了给 p5 增加代码提示,我们不可以使用官网推荐的方式。需要利用 TypeScript 进行模块化的项目构建(会的同学,或者不需要代码提示的同学可以直接跳过这一节)。

这里需要安装一下 Node.js,直接官网下载即可。

以下步骤仅限 Linux 与 MacOS 平台,Windows 不保证可以这么操作!!!

step1 初始化项目

新建一个文件夹,将文件夹拖入 VSCode 打开,切换至英文输入法,同时按下 control + ~ 就可以开启终端。

在终端输入 npm config set registry https://registry.npm.taobao.org && npm init -y && npm i p5 && npm i -D typescript @types/p5 parcel-bundler && ./node_modules/.bin/tsc --init 请初学者直接复制粘贴并且回车,不要尝试自己输入。

这时候可以发现我们的文件夹里出现了几个文件,并且他们全都不需要你去关心

- 你的文件夹名称
  - node_modules
  - tsconfig.json
  - package.json
  - package-lock.json

打开 package.json 文件,应该长这样:

{
  "name": "你的文件夹名称",
  .....
}

step2 创建启动脚本

我们在第二行插入一些东西(一样请直接复制,不要尝试自己打):

{
  "scripts": {
    "start": "./node_modules/.bin/parcel ./src/index.html --no-cache",
    "build": "./node_modules/.bin/parcel build ./src/index.html --no-cache -d build"
  },
  "name": "你的文件夹名称",
  .....
}

step3 创建 HTML 文件

接着我们建立 src 文件夹,并在其中新建我们的 HTML / CSS 文件:

- 你的文件夹名称
  - node_modules
  - tsconfig.json
  - package.json
  - package-lock.json
  - src
    - index.html
    - style.css

src 是之后我们唯一需要关注的文件夹。

step4 启动项目

照常的写你的代码,和之前没有任何区别。然后随便在 HTML 中输入一些标签和字符,在终端中输入:npm run start 并等待一会儿,待显示出

Server running at http://localhost:1234
✨  Built in xxxx.

之后,方可打开浏览器,输入他输出的网址。

此时显示了你刚刚在 HTML 中写的文字即是成功了。

step5 创建 TypeScript 文件

首先在 src 中创建 main.ts 文件,并在 html 中引入。

- src
  - index.html
  - style.css
  - main.ts

因为 p5 的特殊性质,所以无法在 js 文件中提供完整的代码提示,必须使用 typescript。

step6 书写 p5

翻看 p5 的源代码我们发现,p5 本身是一个构造函数,接受两个参数,第一个是一个函数,函数接受一个参数,我们可以通过这个参数实现代码提示:

// main.ts

import P5 from 'p5';

const sketch = (p: P5) => {
  p.setup = () => {
    p.background(0);
  };

  p.draw = () => {
    p.background(0);
    p.fill(255);
    p.ellipse(0, 0, 25, 25);
  };
};

p5 的第二个参数是一个 HTML 元素,意思是我们可以将画布放到这个元素中去。

// index.html

<body>
  <div id="app"></div>

  <script src="./main.ts"></script>
</body>

这时候我们就可以使用 new P5(sketch, document.querySelector('#app')); 来挂载画布了。

(完)

(0)

相关推荐

  • React + Electron封装并打包成桌面应用

    Electron是什么 ​Electron 是一个由 GitHub 开发的开源库,通过将 Chromium) 和Node.js 组合并使用 HTML,CSS 和 JavaScript 进行构建 Mac ...

  • Node.js 入门你需要知道的 10 个问题

    前端技术优选 以下文章来源于Nodejs技术栈 ,作者五月君 本文为您分享「Node.js 入门你需要知道的 10 个问题」这些问题可能也是面试中会被问到的,当然问题不仅仅是这 10 道,因此,最近开 ...

  • 如何使用 Visual Studio Code 调试 Angular Schematics 实现

    How to Debug an Angular Schematic using Visual Studio Code 能够在代码执行时调试和遍历代码是我们开发工作流程的基础.这是一项必不可少的功能,使 ...

  • npm的下载与安装

    npm的下载与安装

  • 关于 JS 模块化的最佳实践总结

    模块化开发是 JS 项目开发中的必备技能,它如同面向对象.设计模式一样,可以兼顾提升软件项目的可维护性和开发效率. 模块之间通常以全局对象维系通讯.在小游戏中,GameGlobal 是全局对象.在小程 ...

  • 使用 Node.js Express 的最佳实践

    Production best practices: performance and reliability 本文讨论部署到生产的 Express 应用程序的性能和可靠性最佳实践. 这个话题显然属于& ...

  • 关于 Node.js 应用里使用 winston 进行日志记录的最佳实践

    Logging with Winston and Node.js 假设您有一个在生产环境中运行的应用程序,每天有数百万用户赚取数千美元.应用程序可能存在错误的原因有多种,作为开发人员,您需要找出原因并 ...

  • 7种人力资源最佳实践

    什么是人力资源最佳实践? 最佳实践是一套通用的人力资源管理流程和行动.在人力资源管理研究中,有两种关于如何管理人员的思想流派:第一个是最合适的,第二个是最佳实践. 最合适的观点指出,为了增加价值,人力 ...

  • 培训的定义、作用和最佳实践

    一.什么是人力资源开发? 人力资源开发一词最早是在1969年提出的,指的是劳动力的培训,教育和发展.它旨在弥合学校教育和工作场所要求之间的差距. 在早期,HRD会进行严格的动手培训,重点是掌握硬技能. ...

  • 从最佳实践的焦虑中解脱出来

    几乎每天都会出现关于最佳实践的头条新闻.例如: 1.参加一个会议:"XX公司会议创新管理提高效率,我们现在没有." 2.行业文章:"人力资源部即将消失." 3. ...

  • 中国电信MEC最佳实践白皮书

    大数据.云计算.AI 等新一代信息技术的高速发展,在为新兴互联网行业提供强劲驱动之外,也在引领传统行业实施数字化.智能化转型,并催生出智能制造.智慧金融等一系列全新智能产业生态.在中国电信 MEC 平 ...

  • go-zero解读与最佳实践(上)

    本文有『Go开源说』第三期 go-zero 直播内容修改整理而成,视频内容较长,拆分成上下篇,本文内容有所删减和重构. 大家好,很高兴来到"GO开源说" 跟大家分享开源项目背后的一 ...

  • 160页PPT学习华为集成产品研发最佳实践之IPD(附下载)

    华为在整个企业内部改革中最重要的两个项目一个是ISC(集成供应链),另外一个就是IPD.用任正非的话讲,这两项改革关系到华为的生死存亡.其中IPD的项目是先行项目也是重点. 今天我们学习下华为的IPD ...