p5.js实现细胞免疫动画


前言

前段时间写了个小demo,要求使用p5绘制一个细胞免疫的流程,因为是临时帮的忙只有一天多的开发时间,但是基本的流程都实现了,记录一下。


准备工作

vscode初始化p5项目

p5.js 是一个JavaScript的函数库,它对canvas 2D绘图进行了比较方便的封装,使得不怎么熟悉这方面的人也能进行可视化开发,p5有线上开发环境:https://editor.p5js.org/。在本地使用安装p5直接使用node命令即可:

npm install p5js

因为我已经有了改库的源文件,所以我的项目的文件目录结构如下:

index.html -- 页面入口
p5.js -- 依赖文件1
p5.sound.min.js -- 依赖文件2
sketch.js -- 自己写的代码
style.css -- 样式文件

在这里插入图片描述

本地运行项目

本地运行p5推荐两个方法,我采用第二个

  • 通过安装并运行http-server本地启动浏览器
  • vscode 安装插件Go-Live,直接点击即可在浏览器自动启动

在这里插入图片描述

免疫过程

接下来是主逻辑的书写,官网api参考:https://p5js.org/reference/,细胞免疫过程分为五步来写,没有开发按钮,通过点击屏幕进行下一步动画,整体过程还是比较麻烦的,附主要代码。

  • 绘制简要的细胞:细胞壁、红细胞、内部细胞
  • 病毒出现,红细胞向病毒靠拢
  • 释放信号细胞传递信息给内部细胞
  • 内部细胞与信号细胞结合,生成免疫细胞
  • 免疫细胞攻击病毒,病毒消失

1 细胞结构

将canvas的尺寸定为500*500大小,画一条线简单代表细胞壁
在这里插入图片描述

// 绘制细胞壁
bezier(
      0, 150,
      200,170,
      250,350,
      300,500
    );
// 红细胞类
class RedCeil {
  constructor(startX, startY) {
    this.x = startX;
    this.y = startY;
  }
  update(x, y) {
    //movement
    this.x += x;
    this.y += y
  }
  display() {
    push();
    translate(this.x, this.y);
    noStroke();
    fill('red');
    ellipseMode(CENTER);
    circle(0, 0, 15);
    fill(230, 10, 80)
    pop();
  }
}

2 病毒出现

在这里插入图片描述

// 添加病毒类需要使用mousePressed方法获取点击位置
function mousePressed() {
  //···
    if (hasVirus) return
   //···
    // 添加病毒
    let v = new Virus(mouseX, mouseY);
   //  console.log([mouseX, mouseY], v)
    hasVirus = true
    virusPosition.push(mouseX, mouseY)
    virusList.push(v);

3 信号细胞运动

在这里插入图片描述

// 添加病毒类需要使用mousePressed方法获取点击位置
function mousePressed() {
  //···
    if (hasVirus) return
    // ···
    // 提前生成信号细胞的点位,在病毒周边
    signCellPosition.push(
      [mouseX,mouseY-15],
      [mouseX-15,mouseY+10],
      [mouseX+15,mouseY-10],
      [mouseX+15,mouseY+15],
      [mouseX-15,mouseY-15],
    )
    signCellPosition.forEach((item) => {
      distanceXYB.push([BCellPosotionList[0][0] - item[0] , BCellPosotionList[0][1] - item[1] ])
    })

4 出现免疫细胞

在这里插入图片描述

  // 抗体细胞展示--抗体细胞的生命周期
  if (antiList.length) { // 病毒展示
    for (let i = 0; i < antiList.length; i++) {
    antiList[i].display()
    if ((step==4) && (!inScoped(antiList[i].x, antiList[i].y, virusList[0].x, virusList[0].y, 10))){
      antiList[i].update(distanceXYANTI[i][0] * Math.random() / 100, distanceXYANTI[i][1] * Math.random()/ 100);
    }
    }
  // ···
  // 停止运动的时机
  function inScoped(x, y, x0, y0, limit) {
    let lx = x - x0
    let ly = y - y0
    let distance = Math.pow(lx * lx + ly * ly, .5)
    return distance < limit
  }

5 病毒被消灭

在这里插入图片描述

// 死亡的病毒 随机生成点
class DeadVirus {
  constructor(startX, startY) {
    this.x = startX;
    this.y = startY;
  }
  display() {
    push();
    translate(this.x, this.y);
    noStroke();
    stroke('blue')
    point(0, 0);
    fill(230, 10, 80)
    pop();
  }	
// 随机点模拟死亡病毒
for (let i=0; i<50; i++){
        let dv = new DeadVirus((Math.random()*2-1) * 10 + virusPosition[0], (Math.random()*2-1) * 10 + virusPosition[1] )
        pointList.push(dv)
}

总结

因为开发时间有限,整体效果比较简陋。动画效果的关键是获取起始位置到目标位置的相对距离,在到达目标位置之前,在动画函数中都判断下是否到达了目标附近,若未到达了就继续运动,否则结束运动。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值