老慜的A5作业——p5.js &动态、周期、随机、面向对象

A5 “运动”主题的创意编程习作

终于到了这学期最后一个编程习作了,来看看最后这学期都憋出来什么玩意吧!

  1. A4pluse,上次作业中对蝴蝶的飞舞动作进行了优化,并且增加了一些环境细节,日夜更替有周期,但是无规则的运动没有周期。代码很容易读,只做了简单的注释
    直接看效果:

在这里插入图片描述
完整代码:

 xoff=0;
 yoff=10000;

 bgc=225;//背景亮度
function setup() {
  createCanvas(500, 500);
}

function draw() {
  background(bgc);
  drawSun();//白天
  drawMoon();//夜晚
  drawmountain();//山峦
  move();//蝶舞
  drawbutterfly();//蝶
}

function drawSun()
{
  fill(205,0,0);
  noStroke();
  ellipse(width/2+width/2*cos(millis()/4000),width/1.5+width/2*sin(millis()/4000),20+40*noise(xoff),20+40*noise(xoff));//太阳移动
    bgc=50+175*sin(millis()/4000+PI);//背景亮度变化
}

function drawMoon()//与太阳运动相差PI相位
{
  fill(200,200,100);
  noStroke();
  ellipse(width/2+width/2*cos(millis()/4000+PI),width/1.5+width/2*sin(millis()/4000+PI),20+20*noise(xoff),20+20*noise(xoff));

}

function move()//柏林噪声的移动模式
{
  xoff = xoff + 0.005;
  yoff= yoff+0.005;
  x= noise(xoff) * width;
  y= noise(yoff)*height;
  translate(x,y)
  rotate(-PI/2*noise(yoff))
}

function drawmountain()//基于噪声的山峦画法
{
    for(var i=1;i<=9;i++)
      {
    for (let x=0; x < width; x++) 
    {
    let noiseVal = noise(i*10+x/100-xoff*i/1.2);//控制山的移动,实际是取随机的范围移动
      if(bgc>100)
    stroke(bgc/i-10);
      else
        stroke(100/i);
    line(x, height*3/(10-i)+noiseVal*height/2, x, height);
    }
     }
}

function drawbutterfly()//基于随机性质与贝塞尔曲线的翅膀震动,D为震动幅度
{
  noStroke();
  fill(150,20,20);
  ellipse(0,0,8,10);
  arcline0424(5,0,20+50*noise(yoff),-25+10*noise(yoff),20);
  arcline0424(5,0,20+50*noise(yoff),25+10*noise(yoff),20);
  fill(100,20,20);
  arcline0424(5,0,30+50*noise(yoff),50+10*noise(xoff),60);
  arcline0424(5,0,30+50*noise(yoff),-50+10*noise(xoff),60);
}

function arcline0424(x1,y1,x2,y2,D)
{
  bezier(x1,y1,x1+(x2-x1)/3+D/2-random(D),y1+(y2-y1)/3+D/2-random(D),x1+2*(x2-x1)/3+D/2-random(D),y1+2*(y2-y1)/3+D/2-random(D),x2,y2);
  
}

function arclinepluse0424(x1,y1,x2,y2,D)//贝塞尔曲线绘制
{
  x3=x1+(x2-x1)/3+D/2-random(D);y3=y1+(y2-y1)/3+D/2-random(D);
  x4=x1+(x2-x1)/3*2+D/2-random(D);y4=y1+(y2-y1)/3*2+D/2-random(D);
  arcline0424(x1,y1,x3,y3,D);
  arcline0424(x3,y3,x4,y4,D);
  arcline0424(x4,y4,x2,y2,D);
}

  1. 《跃动树莓》
    两个周期函数的组合的华丽碰撞加上一点点随机性。灵感来自于陈伟老师的一个智能算法实验的拓展,可以观察到周期性的组合带来的绝美画面,这边的gif演示掉帧且限制在5M以下,实际效果大家可以复制下面的代码实际跑一下看看。
    (代码量很少,但效果是真的好)

在这里插入图片描述



var col;//控制颜色
var freq = 0.000001; //步长
var r;//半径

function setup() {
  createCanvas(600, 600);	
}

function draw() 
{
    background(25*noise(millis()/2000));    //会呼吸的宇宙背景          
    translate(300, 300);  
    rotate(millis()/2000);//随时间旋转
    ellipseMode(RADIUS); //以半径模式画圆
    drawstar(millis()/30000);
}

function drawstar(rate)
{
    
  for (var i=0; i<200; i ++) {  // 粒子总数
    cir= 200 + 175*sin(millis()*freq*i);    //粒子基础位置
    col=map(cir,25,375,175,0);  //颜色映射
    r=map(cir,25,375,5*noise(i),15*noise(i));  //圆半径的计算,由远及近变大
    //r=map(cir,25,375,2,10); 
    fill(col,col,200*noise(millis()/2000));//紫红为主色调
    noStroke();
    ellipse(cir*cos(i), cir*sin(rate*i),r,r);  //周期核心
          
 }	
}

3.《追逐》 随机游走&物理仿真&3维绘图&有点意思的函数实现类的功能的p5.js 带着粒子拖尾的追随体,通过修改受力与速度来追着目标跑
在这里插入图片描述
小球在三维空间中平滑随机游走,追随体以小球的位置作为目标实时修正加速度与速度。简化了重量等概念实现的伪物理仿真效果。
由于这种实现面向对象的方法是第一次遇到,所以给代码做了详尽的注释,这里就不多做介绍了。

var boxSz = 200;//目标物移动的立方体半径大小
var t;//目标物
var seekers = [];//追逐者群

function setup() {
    createCanvas(windowWidth, windowHeight, WEBGL);//3D画布

    t = new Target();//生成一个目标
    for (var i = 0; i < 20; i++) {
        seekers[i] = new Seeker();//生成n个追逐者
    }

}

function draw() {
    background(0);
    translate(0, 0, -boxSz);//把目标物移动到屏幕中间
    rotateY(frameCount * 0.002);//每帧旋转,增强空间感
    rotateX(frameCount * 0.004);//每帧旋转,增强空间感

    t.move();//目标平滑移动
    t.display();//display

    for (var i = 0; i < seekers.length; i++) {
        seekers[i].update();
        seekers[i].seek(createVector(t.pos.x, t.pos.y, t.pos.z));
        seekers[i].display();
    }//更新每个追随者及其拖尾

    drawBox();//画出空间盒子,增强纵深感

}



function Seeker() {

    this.pos = createVector(random(-boxSz * 2, boxSz * 2), random(-boxSz * 2, boxSz * 2), random(boxSz * 2, boxSz * 4));//初始位置
  
    this.vel = createVector(random(-2, 2), random(-2, 2), random(-2, 2));//初始速度
    this.acc = createVector(0, 0, 0);//初始加速度
    this.sz = random(4,8);//尺寸
    this.maxSpeed = random(10, 20);//速度
    this.maxForce = random(0.05, 0.2);//施加力
    this.trail = [];//拖尾群
    this.trailMax = random(5,20);//拖尾数目
  
    this.display = function() {
        stroke(180,180,0);
        push();
        translate(this.pos.x, this.pos.y, this.pos.z);
        sphere(int(this.sz), int(this.sz));
        pop();//画出本体

        for (var i = 0; i < this.trail.length; i++) {
            var pos = this.trail[i];//每次更新一个拖尾元素的状态
          cor=map(i,0,this.trail.length,0,160);//拖尾颜色渐弱,使用map映射
            stroke(cor,cor,20);//色彩填充
            push();
            translate(pos.x, pos.y, pos.z);
            r=map(i,0,this.trail.length,0,this.sz)//尺寸渐弱、map映射
            sphere(int(r), int(r));//拖尾大小渐弱
            pop();
        }//画出拖尾
    }

    this.update = function() {
        this.vel.add(this.acc);//每帧速度变化受加速度影响
        this.pos.add(this.vel);//位置受速度影响(简化了时间的概念)
        this.acc.mult(0);//加速度重置

        if (this.trail.length > this.trailMax) {
            this.trail.splice(0, 1);
        }//超出最大尾迹的拖尾不显示

        if (frameCount % 5 == 0) {
            var v = createVector(this.pos.x, this.pos.y, this.pos.z);
            this.trail.push(v);//每五帧更新一个拖尾元素
        }
    }

    this.applyForce = function(force) {
        this.acc.add(force);//施加加速度(力,这里简化了重量的概念)
    }
  
    this.seek = function(target) {
        var desired = p5.Vector.sub(target, this.pos);
        desired.setMag(this.maxSpeed);//最大速度约束
        var steering = p5.Vector.sub(desired, this.vel);
        steering.limit(this.maxForce);//最大力约束
        this.applyForce(steering);
    }
  
}


function Target() {
    this.pos = createVector(random(-boxSz, boxSz), random(-boxSz, boxSz), random(-boxSz, boxSz));//生成时取范围内的随机位置
  
    this.display = function() {
        fill(255, 100, 0);
        push();
        translate(this.pos.x, this.pos.y, this.pos.z);
        noStroke();
        sphere(20);
        pop();
       stroke(255,255,0);  
    }//画出目标物 
  
   this.move=function()//更新目标物的位置,使柏林噪声
      {
      this.pos.x=boxSz-2*boxSz*noise(millis()/5000);//让平滑噪声的取值错开
      this.pos.y=boxSz-2*boxSz*noise((millis()+500000)/5000);
      this.pos.z=boxSz-2*boxSz*noise((millis()+1000000)/5000);
      }
}


function drawBox() //画出空间盒子,增强纵深感
{
    stroke(0,75,175);
    strokeWeight(5); // Thicker
    line(-boxSz, -boxSz, boxSz, boxSz, -boxSz, boxSz);
    line(-boxSz, boxSz, boxSz, boxSz, boxSz, boxSz);
    line(-boxSz, -boxSz, boxSz, -boxSz, boxSz, boxSz);
    line(boxSz, -boxSz, boxSz, boxSz, boxSz, boxSz);
    line(-boxSz, -boxSz, -boxSz, boxSz, -boxSz, -boxSz);
    line(-boxSz, boxSz, -boxSz, boxSz, boxSz, -boxSz);
    line(-boxSz, -boxSz, -boxSz, -boxSz, boxSz, -boxSz);
    line(boxSz, -boxSz, -boxSz, boxSz, boxSz, -boxSz);
    line(-boxSz, -boxSz, boxSz, -boxSz, -boxSz, -boxSz);
    line(-boxSz, boxSz, -boxSz, -boxSz, boxSz, boxSz);
    line(boxSz, -boxSz, boxSz, boxSz, -boxSz, -boxSz);
    line(boxSz, boxSz, -boxSz, boxSz, boxSz, boxSz);

}

4.类实现面向对象的简单粒子系统(一个经典的连线例子)
在这里插入图片描述
感觉,p5里的类也太难用了吧,代码写出来还不好看

const particles =  [];
const number=50;
 
function setup() {
     createCanvas(500, 500);
     const particlesLength =100 ;// 粒子数量
     for(let i=0;i<particlesLength;i++) 
     {
        particles.push(new Particle());
     }
}

function draw() {
  background('#34495e');
  particles.forEach((p,index) => {
    p.customUpdate();
    p.customDraw();
    p.checkParticles(particles.slice(index));}
                   );
  mouse=createVector(mouseX,mouseY);
  
}
     
class Particle {
  constructor() {
  this.pos = createVector(random(width),random(height));
  // 粒子的大小
  this.size = random(5,10);
  // 移动速度
  this.vel = createVector(random(-2,2),random(-2,2));
            }
   customDraw() {
    // 绘制单个粒子
   noStroke();
   fill('#1abc9c');
   circle(this.pos.x,this.pos.y,this.size);
            }
  
   customUpdate(){
     this.pos.add(this.vel);
     this.customEdges();
   }
  
  customEdges() {
   if(this.pos.x < 0 || this.pos.x > width) {
     this.vel.x *= -1;
                }
   if(this.pos.y < 0 || this.pos.y > height) {
     this.vel.y *= -1;
            }
       }
            // 粒子连线
            checkParticles(particles) {
                particles.forEach(particle => {
                    // 距离矩阵来限制范围
                    const d = dist(this.pos.x, this.pos.y,particle.pos.x,particle.pos.y);
                     if(d >50){
                        stroke(255,0,0);
                        //line(this.pos.x, this.pos.y,particle.pos.x,particle.pos.y);
                      this.size=this.size-0.0001;
                    }
                   if(d < 100){
                        stroke('#3498db');
                        line(this.pos.x, this.pos.y,particle.pos.x,particle.pos.y);
                      this.size=this.size+0.0001;
                    }
                })
            }
        }
 
  • 3
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值