本次使用P5.js作为交互作品的创作平台,以《Nature of Code》这本书里面介绍的三种技术为基础展开创作,分别是‘向量’、‘力’和‘粒子系统’,将这三种技术融合在一起创作出粒子的运动效果,还有用户交互对粒子产生的影响(主要指鼠标运动对粒子产生的力的作用)。力图可以充分展现出交互对动画产生的显著影响。
本作品主要通过粒子系统模拟喷泉的效果,众所周知,喷泉的炫酷效果都是事先通过程序预先设定好的,无论外力怎么响应,都不会改变喷泉原先的展示效果。
本作品反其道而行之,通过粒子系统创作一种可以随意通过交互改变喷泉状态的交互式喷泉。
我把这种交互式喷泉想象为——当用户不与喷泉产生交互时,喷泉是静态的,宛如一潭安静的湖水,如下图所示
而与喷泉产生交互的方式是——用户移动鼠标靠近底部的‘水潭’,当鼠标的距离与‘水潭’足够近时,鼠标就会对‘水潭’中的粒子产生力的作用,粒子在力的作用下产生向上的运动,同时受到重力的作用,形成喷泉的效果。
大家可以把这种交互形式想象成隔空取物的魔幻效果!想象自己是一名武功盖世的武林高手,可以举手投足间就让一潭湖水变幻出各种各样的喷泉效果!!!
用户可以随意拖动鼠标到屏幕下方接近水潭的位置,当系统检测到鼠标距离粒子的距离足够近时,就会对粒子产生吸引力,从而导致粒子往鼠标的位置运动,产生喷泉效果,而当粒子运动到鼠标位置上方时,这时候鼠标对粒子不再产生吸引力,粒子只受到重力的作用,这时候粒子就会很自然地产生向下的匀加速运动,从而完美地呈现了真实的喷泉效果。
是不是十分的炫酷和有趣!
本次交互设计采用P5.js为平台,采用了力,向量和粒子系统三种技术进行创作,下面一起来看看详细的技术分析。
I:粒子类
function Particle(x, y) {
this.lastPos = new p5.Vector(x, y);
this.pos = new p5.Vector(x, y);
this.vel = new p5.Vector(0, 0);
this.acc = new p5.Vector(0, 0);
this.size = random(2, 20);
this.h = globalHue;
}
首先编写一个粒子类用于保存粒子的各种属性——位置、速度、加速度、还有粒子的大小,颜色。
将粒子的位置、速度、加速度都设置为向量的形式,这样有利于模拟在真实世界中喷泉的运动效果
粒子的大小随机,颜色随着时间的变化产生渐变
II:
function setup() {
createCanvas(windowWidth, windowHeight);
colorMode(HSB, 360);
mouseX = width / 2;
mouseY = height / 2;
}
初始化窗口设置
采用HSB的颜色模式,这样可以方便地实现颜色的渐变效果
鼠标初始的位置设置为屏幕中心点
III:
function draw() {
noStroke();
fill(0, 5);
rect(0, 0, width, height);
for (var i = 0; i < spawnPerFrame; i++) {
allParticles.push(new Particle(random(width), height));
}
绘制窗口
每一帧减少spawnPerFrame个粒子,防止粒子过多造成系统卡顿
IV:
for (var i = allParticles.length - 1; i > -1; i--) {
allParticles[i].acc.add(new p5.Vector(0, allParticles[i].size * 0.01));
// Quick check to avoid calculating distance if possible.
if (abs(allParticles[i].pos.x - mouseX) < mouseSize) {
d = dist(mouseX, mouseY, allParticles[i].pos.x, allParticles[i].pos.y);
if (d < mouseSize) {
var vec = new p5.Vector(mouseX, mouseY - mouseSize);
vec.sub(new p5.Vector(allParticles[i].pos.x, allParticles[i].pos.y));
vec.normalize();
allParticles[i].vel.add(vec);
allParticles[i].h += 1.5;
if (allParticles[i].h > 360) {
allParticles[i].h = 0;
}
}
}
allParticles[i].vel.add(allParticles[i].acc);
allParticles[i].pos.add(allParticles[i].vel);
allParticles[i].acc.mult(0);
检测粒子与鼠标的距离,并且对粒子施加响应的加速度,同时检测粒子是否超出屏幕
V:
stroke(allParticles[i].h, 360, 360);
strokeWeight(allParticles[i].size);
line(allParticles[i].lastPos.x, allParticles[i].lastPos.y,
allParticles[i].pos.x, allParticles[i].pos.y);
allParticles[i].lastPos.set(allParticles[i].pos.x, allParticles[i].pos.y);
if (allParticles[i].pos.y > height || allParticles[i].pos.x < 0 || allParticles[i].pos.x > width) {
allParticles.splice(i, 1);
}
}
globalHue += 0.15;
if (globalHue > 360) {
globalHue = 0;
}
}
绘制粒子的运动轨迹,并将颜色设置为随时间变化而变化
这次的交互媒体创作的分享到这里就差不多结束了,这次创作对我来说也是一种全新的体验,在将新技术运用到程序中的同时,我也在尝试一种以前没有尝试过的主题——试图在交互的世界中创作一种与现实世界的体验与众不同,但又和真实世界紧紧联系的交互体验,希望用户可以在交互的过程中获得与真实世界中不一样的乐趣,这是我的设计理念所在,希望大家喜欢这次的作品,谢谢~