互动媒体技术——基于p5.js实现创意动态交互自画像:走进奇妙的歌手音乐世界!

本文主要是介绍互动媒体技术——基于p5.js实现创意动态交互自画像:走进奇妙的歌手音乐世界!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

博文索引目录:
1. 引言
2. 自画像功能展示及使用说明
3. 功能实现

  • 3.1 交互一——GUI界面
  • 3.2 交互二——音乐播放器
    • 3.2.1 播放/暂停
    • 3.2.2 切歌
    • 3.2.3 倍速与音量
  • 3.3 交互三——动态灯光背景
    • 3.3.1 普通灯光
    • 3.3.2 闪烁灯光
  • 3.4 交互四——闪烁会动的眼睛
  • 3.5 交互五——会唱歌的嘴巴
  • 3.6 交互六——根据音量互动的彩虹喇叭
  • 3.7 交互七——录音功能
  • 3.8 自画像其他画线代码

4. 总结


1. 引言

这一次互动媒体技术的作品是利用用p5.js实现了自己的创意自画像,因为我非常喜欢音乐,所以本次创意自画像全部围绕音乐这个主题。因为太喜欢音乐了,所以做的时候一发不可收拾啦。接下来,让我带领你们进入奇妙的音乐世界吧~启程咯!

2. 自画像功能展示及使用说明

接下来我将详细展示我的自画像各功能的交互,由于交互较多,刚进入自画像的图片我采用了静态图,而后每一个功能我都使用动态图进行展示。

初始进入界面时:
可以在左上角小字看到,我是中国90后顶尖流行歌手陈明炜,身穿燕尾服,手拿金话筒。
在这里插入图片描述
通过GUI界面,可以修改背景颜色、灯光颜色和灯光样式:
在这里插入图片描述
操作简易的音乐播放器,可以选择想要演唱的歌曲,演唱歌曲时歌名会显示在右下方。我的嘴巴在演唱时会张合,如果暂停演唱,我的嘴巴就会闭合。(GIF图显示不出声音,如果需要听声音可以加载html文件或者看文件夹中的介绍视频)
在这里插入图片描述
在演唱过程中还能调节音量和音速。同时还可以切歌。
在这里插入图片描述
我的眼睛一直闪烁着,而且眼珠会随着鼠标位置的移动而移动。
在这里插入图片描述
彩虹喇叭获取电脑麦克风的音量,音量越大,扩张越大。
在这里插入图片描述
录音功能,即按下空格键开始录音,第二次按下停止录音,第三次按下可以保存音频文件。(可重复录制和保存)
在这里插入图片描述
需要说明的是,由于用到了本地声音资源的加载,涉及到跨域权限的问题,在项目运行时为了能听到声音,需要进行一些配置,具体配置请参考:
js加载跨域文件报错多种解决与配置方法

3. 功能实现

  • 3.1 交互一——GUI界面

p5.js的GUI界面程序学习请参考GitHub代码:p5.js—GUI

代码如下所示,先设置界面的各个选项参数,然后在setup()函数中用createGui()创建界面,再通过addGlobals()将各设置添加到GUI界面中,如果在界面中选择改变一些变量的值,那么这些变量在draw()函数中绘制就会改变,从而从GUI能够改变一些参数的值。这里需要说明的是,为了在界面中呈现中文,我的每个界面选项的变量都用了中文,但在实际编程中还是不建议采用这种方法,虽然能运行,但太不规范了。

//界面
var gui;
//调整衣服、灯光颜色、灯光样式
var 背景颜色 = [255,168,211];
var 灯光颜色 = [255,0,0];
var 灯光样式 = ['点阵','闪动点阵','闪动方阵'];
//曲目选择栏
var 演唱曲目 = ['无','《我的名字》','《喜欢你》','《太空》','《Shape of you》','《玫瑰少年》'];  
//音量
var 音量 =0.5;
//速度
var 速度=['1.0倍速','0.5倍速','2.0倍速'],speed;
//播放/暂停
var 是否开唱=['演唱','暂停'];// 函数setup() : 准备阶段
function setup() 
{createCanvas(windowWidth, windowHeight);background(背景颜色);// 创建GUI界面gui = createGui('中国90后顶尖流行歌手:陈明炜');colorMode(RGB, 255);//滑条最小、最大值和步长sliderRange(0.0, 1.0, 0.1);//为界面增加各选项gui.addGlobals('背景颜色', '灯光颜色','灯光样式','演唱曲目','音量','速度','是否开唱'); ......//其他代码
}
  • 3.2 交互二——音乐播放器

在GUI界面中,一个重要的实现就是简易音乐播放器,它可以播放音乐,可以暂停或者继续播放,可以实现切歌功能,也可以改变倍速与音量。

  • 3.2.1 播放/暂停

播放与暂停之间的切换由一个isplay变量实现,默认是不开唱的,如果界面中选择的是演唱,且演唱曲目是无,则开始播放音乐,并将isplay置为true;如果界面中选择的是暂停,就用pause()使音乐暂停,同时置isplay为false.

//默认不开唱
var isplay=false;
switch(是否开唱)
{case '演唱':if(!isplay&&演唱曲目!='无'){song.play();isplay=true;}break;		case '暂停':song.pause();isplay=false;break;
}
  • 3.2.2 切歌

切歌功能其实夹带在普通播放功能下,每帧通过判断当前所选择的演唱曲目是什么来进行操作,如果是“无”,就停止播放;如果是其他曲目,则先让原来的音乐暂停,再重新创建一个audio,最后让它自动播放。这里最重要的是一个条件判断,即当前演唱曲目与上一帧的曲目是否相同,如果相同,则不切换,只有不同时才代表切歌了。

//歌曲变量  
var song;  
//上一帧的曲目
var oldsong; function setup() 
{......//其他代码song = createAudio();......//其他代码
}// 函数draw():作画阶段
function draw()
{......//其他代码//更新当前所选的音乐switch(演唱曲目){case '无':song.stop();isplay=false;break;case '《我的名字》':if(演唱曲目!=oldsong){song.pause();song = createAudio('../music/我的名字.mp3');	song.autoplay(true);}break;case '《喜欢你》':if(演唱曲目!=oldsong){song.pause();song = createAudio('../music/喜欢你.mp3');song.autoplay(true);	}break;case '《太空》':if(演唱曲目!=oldsong){song.pause();song = createAudio('../music/太空.mp3');	song.autoplay(true);	}break;case '《Shape of you》':if(演唱曲目!=oldsong){song.pause();song = createAudio('../music/Shape of you.mp3');	song.autoplay(true);	}break;case '《玫瑰少年》':if(演唱曲目!=oldsong){song.pause();song = createAudio('../music/玫瑰少年.mp3');	song.autoplay(true);	}break;}oldsong=演唱曲目;......//其他代码
  • 3.2.3 倍速与音量

倍速与音量的设置也是非常简单,只需获取相应的值,用volume()与speed()进行设置即可。

//调整播放速度
switch(速度)
{case '0.5倍速':speed=0.5;break;case '1.0倍速':speed=1.0;break;case '2.0倍速':speed=2.0;break;
}
song.volume(音量);
song.speed(speed);
  • 3.3 交互三——动态灯光背景

这里的动态灯光效果用到了上一次互动媒体作业中我所临摹的灯光效果图,改进了参数以后的结果就是本次演示的结果,具体变换规律与数学原理请参考我的上一篇博文:
互动媒体技术——基于p5.js实现动态图形临摹与拓展:炫彩光影的千变万化!

  • 3.3.1 普通灯光
    这是原来的临摹图,灯光的中心在中心(200,200)处,本作品中只需将中心改到(windowWidth/2,windowHeight/2)处,并修改各区域所对应直线的斜率判断即可。
    在这里插入图片描述
    代码如下:
// 函数draw():作画阶段
function draw()
{//屏幕中心点坐标var xcen=windowWidth/2;var ycen=windowHeight/2;//程序运行的时间(单位:秒)t=millis()/1000;......//其他代码//画8*8的点阵for(i=0;i<8;i++)for(j=0;j<8;j++){fill(灯光颜色); stroke(灯光颜色);var x=xpos+i*windowWidth/8;  //实际画的时候点的x坐标var y=(t*78)%windowHeight+ypos+j*windowHeight/8;  //实际画的时候点的y坐标//如果点运动到画布下界,则从上界开始重新往下运动if(y>=windowHeight)y-=windowHeight;//找直线与边界的交点坐标var linex,liney;  //交点的x、y坐标//区域1if ( x<xcen && x>xcen/ycen*y ) {linex=(xcen-x)/(y-ycen)*y+x;liney=0;} //区域2else if( x<xcen && x<=(windowHeight-y)*xcen/(windowHeight-ycen)){linex=0;liney=(ycen-y)/(x-xcen)*x+y;}//区域3else if ( x<xcen && x>(windowHeight-y)*xcen/(windowHeight-ycen)) {linex=(xcen-x)/(y-ycen)*(y-windowHeight)+x;liney=windowHeight;} //区域4else if(x>xcen && x<(windowWidth-xcen)/(windowHeight-ycen)*(y-windowHeight)+windowHeight){linex=(xcen-x)/(y-ycen)*(y-windowHeight)+x;liney=windowHeight;}//区域5else if ( x>xcen && x<=(xcen-windowWidth)/ycen*y+windowHeight) {linex=(x-xcen)/(ycen-y)*y+x;liney=0;} //区域6else{linex=windowWidth;liney=(ycen-y)/(xcen-x)*(windowWidth-x)+y;}var times;   //重复次数switch(i)    //每一列的“灯光”粗细不同{case 0: times=3;break;case 1: times=5;break;case 2: times=10;break;case 3: times=15;break;case 4: times=15;break;case 5: times=10; break;case 6: times=5; break;case 7: times=3;break;}//画直线//如果与竖直边界相交if(linex==0 ||linex==windowWidth){for (var m = 1; m <times ; m++) {line(linex,liney-m,x,y);line(linex,liney+m,x,y);}}//如果与水平底边相交if(liney==windowHeight){var times1=(2.0-times)*(x+y-windowHeight)/x+times;for(var n=1; n< times1; n++){line(linex-n,liney,x,y);line(linex+n,liney,x,y);}}//如果与水平顶边相交if(liney==0){var times2=(times-2.0)*y/x+2.0;for(var k=1; k< times2; k++){line(linex-k,liney,x,y);line(linex+k,liney,x,y);}}line(linex,liney,x,y);}......//其他代码
}
  • 3.3.2 闪烁灯光

闪烁灯光用到了一个随机数函数random(),每一帧都在一定的范围内随机生成圆点或者正方形的边长参数,这样每帧刷新看起来就是闪烁的效果了。

//画点
switch(灯光样式)
{case '点阵':ellipse(x,y,10,10);break;case '闪动点阵':var r=random(30,50);ellipse(x,y,r,r);break;case '闪动方阵':var r1=random(80,120);var r2=random(50,80);rect(x-r1/2,y-r2/2,r1,r2);
}
  • 3.4 交互四——闪烁会动的眼睛

眼睛瞳孔的闪烁与灯光的闪烁原理相同,设置一个小范围的随机数在画圆的参数中即可。如果要瞳孔随着鼠标移动的方向移动,则需要获取鼠标坐标mouseX与mouseY,在画圆的参数中将mouseX、mouseY与随机数结合,调整参数,即可实现效果。这里的系数是经过多次调试以后得到的。

//瞳孔会随鼠标位置移动而移动
//左瞳孔
fill(29,153,180);
ellipse(xcen-70+(mouseX-xcen)/110+random(-0.5,0.5),ycen-55+(mouseY-ycen)/100+random(-0.5,0.5),20,20);
ellipse(xcen-60+(mouseX-xcen)/80+random(-0.5,0.5),ycen-35+(mouseY-ycen)/120+random(-0.5,0.5),10,10);
//右瞳孔
ellipse(xcen+70+(mouseX-xcen)/110+random(-0.5,0.5),ycen-55+(mouseY-ycen)/100+random(-0.5,0.5),20,20);
ellipse(xcen+80+(mouseX-xcen)/80+random(-0.5,0.5),ycen-35+(mouseY-ycen)/120+random(-0.5,0.5),10,10);
  • 3.5 交互五——会唱歌的嘴巴

唱歌时嘴巴张合,不唱时嘴巴闭合,这就可以通过isplay变量来判断是否开唱,嘴巴状态进入两个分支。在张合过程中,为了避免每帧刷新带来的频繁闪动,嘴的两个状态需要设置一定的概率,且尽量一个偏大,一个偏小。另外,这里画嘴用到了贝塞尔曲线,实际上,自画像的大部分都用到了贝塞尔曲线,通过一个非常好的自动生成顶点的软件就能很快画出,但因为我的自画像是根据网页的中心点画的,而不是固定点坐标,这就需要非常非常麻烦的坐标转换,需要一个一个点去加上相同的数。

//嘴巴(当演唱时会动)
if(isplay==false)  //不演唱时
{noFill();stroke(0,0,0);strokeWeight(4);arc(xcen,ycen+20,100,100, QUARTER_PI,PI-QUARTER_PI);
}
else
{var rannum=random(0,1);if(rannum<0.85){noFill();stroke(0,0,0);arc(xcen,ycen+100,100,100, PI + QUARTER_PI,TWO_PI-QUARTER_PI);arc(xcen,ycen+29,100,100, QUARTER_PI,PI-QUARTER_PI);fill(255,0,0);beginShape();vertex(xcen-35,ycen+65);bezierVertex(xcen-11,ycen+61,xcen+20,ycen+58,xcen+34,ycen+65);bezierVertex(xcen+28,ycen+73,xcen-2,ycen+91,xcen-35,ycen+65);endShape();}else{fill(255,0,0);stroke(0,0,0);ellipse(xcen,ycen+65,60,40);}
}
  • 3.6 交互六——根据音量互动的彩虹喇叭

彩虹喇叭主要是通过获取电脑的麦克风,来获取音量,音量大,则麦克风扩散范围大。

//麦克风
var mic;// 函数setup() : 准备阶段
function setup() 
{......//其他代码//麦克风mic = new p5.AudioIn();mic.start();......//其他代码
}// 函数draw():作画阶段
function draw()
{......//其他代码//获取麦克风音量micLevel = mic.getLevel();......//其他代码//彩虹声音stroke(185,0,185);strokeWeight(10);arc(xcen+200,ycen+50,0.3*(height+micLevel*height*5),0.3*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(0,255,255);arc(xcen+205,ycen+45,0.34*(height+micLevel*height*5),0.34*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(60,157,255);arc(xcen+210,ycen+40,0.38*(height+micLevel*height*5),0.38*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(0,255,128);arc(xcen+215,ycen+35,0.42*(height+micLevel*height*5),0.42*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(255,255,0);arc(xcen+220,ycen+30,0.46*(height+micLevel*height*5),0.46*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(255,128,64);arc(xcen+225,ycen+25,0.50*(height+micLevel*height*5),0.50*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(255,0,0);arc(xcen+230,ycen+20,0.54*(height+micLevel*height*5),0.54*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);......//其他代码
}
  • 3.7 交互七——录音功能
    首先需要定义录音器、声音文件、延迟等变量。录音功能的交互实现是基于键盘的,通过键盘响应函数keyPressed()来判断三种状态分别执行开始录制、停止录制和保存音频的操作。这里需要注意,由于是一帧一帧截取音频的,所以如果直接保存得到的音频是卡顿的,有“电音”的效果。所以我们需要添加延迟处理函数,draw()一秒执行60次,所以延迟定为1/60=0.016666…其他参数也须进行反复调整得出。
//录音机
var recorder;
//声音文件
var soundFile;
//按空格键次数
var state=0;
//延迟
var delay;// 函数setup() : 准备阶段
function setup() 
{......//其他代码//录音机recorder = new p5.SoundRecorder();//麦克风与录音机相关联recorder.setInput(mic);//声音文件soundFile = new p5.SoundFile();soundFile.amp(0);//调节录音卡帧delay = new p5.Delay();delay.process(soundFile,0.0166667,0.5,2300);
}//按空格键录音
function keyPressed() 
{
//按下空格键if (keyCode === 32) {if (state === 0 && mic.enabled) {//开始录音recorder.record(soundFile);state++;}else if (state === 1) {//停止录音recorder.stop();state++;}else if (state === 2) {//保存save(soundFile, 'mySound.wav');state=0;//为下一次录音再次配置recorder = new p5.SoundRecorder();recorder.setInput(mic);soundFile = new p5.SoundFile();}}
}
  • 3.8 自画像其他画线代码
    在这一部分我将自画像其他一些没有特别技术含量的纯画线代码贴出来:
	//自画像://里面衣服fill(135,135,135);stroke(0,0,0);ellipse(xcen,ycen+240,240,350);line(xcen-90,ycen+350,xcen+90,ycen+350);//耳朵fill(254,211,169);strokeWeight(4);arc(xcen-125,ycen,80,80, HALF_PI,HALF_PI+PI);line(xcen-125,ycen+35,xcen-155,ycen);arc(xcen+125,ycen,80,80,HALF_PI+PI,HALF_PI);line(xcen+125,ycen+35,xcen+155,ycen);//脸ellipse(xcen,ycen-50,300,315);//下巴arc(xcen,ycen+100,100,80,QUARTER_PI*0.3,PI-QUARTER_PI*0.3);//左眼睛fill(0,0,0);ellipse(xcen-70,ycen-45,55,55);//右眼睛ellipse(xcen+70,ycen-45,55,55);//瞳孔会随鼠标位置移动而移动//左瞳孔fill(29,153,180);ellipse(xcen-70+(mouseX-xcen)/110+random(-0.5,0.5),ycen-55+(mouseY-ycen)/100+random(-0.5,0.5),20,20);ellipse(xcen-60+(mouseX-xcen)/80+random(-0.5,0.5),ycen-35+(mouseY-ycen)/120+random(-0.5,0.5),10,10);//右瞳孔ellipse(xcen+70+(mouseX-xcen)/110+random(-0.5,0.5),ycen-55+(mouseY-ycen)/100+random(-0.5,0.5),20,20);ellipse(xcen+80+(mouseX-xcen)/80+random(-0.5,0.5),ycen-35+(mouseY-ycen)/120+random(-0.5,0.5),10,10);//左眼线noFill();stroke(0,0,0);//strokeWeight(4);arc(xcen-70,ycen-22.5,100,100, PI + QUARTER_PI,TWO_PI-QUARTER_PI);arc(xcen-70,ycen-60,85,85, QUARTER_PI,HALF_PI+QUARTER_PI);//右眼线arc(xcen+70,ycen-22.5,100,100, PI + QUARTER_PI,TWO_PI-QUARTER_PI);arc(xcen+70,ycen-60,85,85, QUARTER_PI,HALF_PI+QUARTER_PI);//鼻子strokeWeight(2);line(xcen,ycen-45,xcen-10,ycen);arc(xcen,ycen+5,20,20, 0, PI);//嘴巴(当演唱时会动)if(isplay==false)  //不演唱时{noFill();stroke(0,0,0);strokeWeight(4);arc(xcen,ycen+20,100,100, QUARTER_PI,PI-QUARTER_PI);}else{var rannum=random(0,1);if(rannum<0.85){noFill();stroke(0,0,0);arc(xcen,ycen+100,100,100, PI + QUARTER_PI,TWO_PI-QUARTER_PI);arc(xcen,ycen+29,100,100, QUARTER_PI,PI-QUARTER_PI);fill(255,0,0);beginShape();vertex(xcen-35,ycen+65);bezierVertex(xcen-11,ycen+61,xcen+20,ycen+58,xcen+34,ycen+65);bezierVertex(xcen+28,ycen+73,xcen-2,ycen+91,xcen-35,ycen+65);endShape();}else{fill(255,0,0);stroke(0,0,0);ellipse(xcen,ycen+65,60,40);}}//左手fill(40,40,40);strokeWeight(4);beginShape();vertex(xcen-90,ycen+90);bezierVertex(xcen-107,ycen+81,xcen-173,ycen+138,xcen-200,ycen+212);bezierVertex(xcen-195,ycen+281,xcen-88,ycen+214,xcen-61,ycen+167);endShape();//右手beginShape();vertex(xcen+90,ycen+260);bezierVertex(xcen+152,ycen+137,xcen+201,ycen+101,xcen+199,ycen+65);bezierVertex(xcen+179,ycen+25,xcen+144,ycen+86,xcen+65,ycen+97);endShape();//左衣服beginShape();vertex(xcen-110,ycen+170);bezierVertex(xcen-203,ycen+420,xcen-130,ycen+416,xcen-1,ycen+237);bezierVertex(xcen+23,ycen+146,xcen+10,ycen+116,xcen-88,ycen+90);endShape();//右衣服beginShape();vertex(xcen+110,ycen+170);bezierVertex(xcen+203,ycen+420,xcen+130,ycen+416,xcen+1,ycen+237);bezierVertex(xcen-23,ycen+146,xcen-10,ycen+116,xcen+86,ycen+90);endShape();//纽扣fill(128,64,64);ellipse(xcen,ycen+180,80,50);//麦克风fill(255,213,11);translate(xcen, ycen);rotate(PI / 4.0);rect(130, -35, 80, 40);quad(210, -30, 250, -30,230,-5,210,-5);rotate(-PI / 4.0);translate(-xcen, -ycen);ellipse(xcen+80,ycen+60,80,80);line(xcen+40,ycen+60,xcen+80,ycen+20);line(xcen+80,ycen+100,xcen+120,ycen+60);line(xcen+52,ycen+32,xcen+102,ycen+93);line(xcen+64,ycen+24,xcen+112,ycen+83);noFill();arc(xcen+40,ycen+20,120,120,0.08*HALF_PI,0.92*HALF_PI);//彩虹声音stroke(185,0,185);strokeWeight(10);arc(xcen+200,ycen+50,0.3*(height+micLevel*height*5),0.3*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(0,255,255);arc(xcen+205,ycen+45,0.34*(height+micLevel*height*5),0.34*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(60,157,255);arc(xcen+210,ycen+40,0.38*(height+micLevel*height*5),0.38*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(0,255,128);arc(xcen+215,ycen+35,0.42*(height+micLevel*height*5),0.42*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(255,255,0);arc(xcen+220,ycen+30,0.46*(height+micLevel*height*5),0.46*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(255,128,64);arc(xcen+225,ycen+25,0.50*(height+micLevel*height*5),0.50*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);stroke(255,0,0);arc(xcen+230,ycen+20,0.54*(height+micLevel*height*5),0.54*(height+micLevel*height*5),PI+1.8*QUARTER_PI,HALF_PI-QUARTER_PI);//头发//填充空白部分fill(160,130,101);noStroke();ellipse(xcen-130,ycen-140,75,75);ellipse(xcen-100,ycen-180,82,82);ellipse(xcen-60,ycen-190,82,82);ellipse(xcen+16,ycen-194,135,135);ellipse(xcen+40,ycen-140,60,60);ellipse(xcen+90,ycen-200,70,70);//填充画线stroke(0,0,0);strokeWeight(4);beginShape();vertex(xcen-80,ycen-200);bezierVertex(xcen-147,ycen-183,xcen-161,ycen-88,xcen-150,ycen-25);bezierVertex(xcen-199,ycen-165,xcen-166,ycen-191,xcen-127,ycen-232);bezierVertex(xcen-86,ycen-257,xcen-99,ycen-268,xcen-20,ycen-244);bezierVertex(xcen+1,ycen-272,xcen+48,ycen-271,xcen+111,ycen-250);bezierVertex(xcen+151,ycen-242,xcen+232,ycen-146,xcen+141,ycen-15);bezierVertex(xcen+189,ycen-109,xcen+129,ycen-197,xcen+64,ycen-228);endShape();beginShape();vertex(xcen-160,ycen-96);bezierVertex(xcen-142,ycen-97,xcen-175,ycen-22,xcen-102,ycen-35);bezierVertex(xcen-138,ycen-28,xcen-114,ycen-90,xcen-100,ycen-169);endShape();beginShape();vertex(xcen-118,ycen-130);bezierVertex(xcen-129,ycen-102,xcen-124,ycen-75,xcen-108,ycen-46);bezierVertex(xcen-108,ycen-87,xcen-105,ycen-122,xcen-87,ycen-144);bezierVertex(xcen-69,ycen-151,xcen-49,ycen-151,xcen-24,ycen-144);bezierVertex(xcen-11,ycen-119,xcen-11,ycen-90,xcen-20,ycen-63);bezierVertex(xcen+10,ycen-93,xcen+5,ycen-136,xcen+11,ycen-170);endShape();beginShape();vertex(xcen-23,ycen-179);bezierVertex(xcen+2,ycen-147,xcen+24,ycen-110,xcen+11,ycen-72);bezierVertex(xcen+35,ycen-81,xcen+41,ycen-137,xcen+30,ycen-169);endShape();beginShape();vertex(xcen+34,ycen-117);bezierVertex(xcen+54,ycen-99,xcen+51,ycen-63,xcen+47,ycen-56);bezierVertex(xcen+66,ycen-85,xcen+69,ycen-103,xcen+67,ycen-152);endShape();beginShape();vertex(xcen+68,ycen-153);bezierVertex(xcen+88,ycen-124,xcen+94,ycen-134,xcen+87,ycen-90);bezierVertex(xcen+111,ycen-126,xcen+97,ycen-157,xcen+77,ycen-180);endShape();beginShape();vertex(xcen+133,ycen-142);bezierVertex(xcen+147,ycen-117,xcen+148,ycen-89,xcen+146,ycen-57);bezierVertex(xcen+164,ycen-92,xcen+162,ycen-122,xcen+157,ycen-164);endShape();beginShape();vertex(xcen+70,ycen-188);bezierVertex(xcen+111,ycen-145,xcen+138,ycen-104,xcen+135,ycen-50);bezierVertex(xcen+157,ycen-114,xcen+143,ycen-176,xcen+130,ycen-180);endShape();//更新文字textStyle(BOLD);textSize(60);textFont('华文琥珀');if(演唱曲目!='无'){switch(演唱曲目){case '《我的名字》':fill(154,170,140);break;case '《喜欢你》':fill(255,168,211);break;case '《太空》':fill(0,128,192);break;case '《Shape of you》':fill(255,128,64);break;case '《玫瑰少年》':fill(230,0,0);}text(演唱曲目, xcen+240, ycen+200);	}

4. 总结

本次的创意自画像我选取了我的爱好和梦想作为主题,化身成为一位当红歌手,以动人的天籁为大家献唱各种流行歌曲。在画的过程中灵感总是肆意迸发,最终产生了这样一幅作品。在整个过程中,我又加深了对p5.js的理解并大大提升了对码绘的兴趣与热情。希望后续能够继续创作出灵感爆棚的作品,加油,小明!

这篇关于互动媒体技术——基于p5.js实现创意动态交互自画像:走进奇妙的歌手音乐世界!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/163414

相关文章

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

揭秘世界上那些同时横跨两大洲的国家

我们在《世界人口过亿的一级行政区分布》盘点全球是那些人口过亿的一级行政区。 现在我们介绍五个横跨两州的国家,并整理七大洲和这些国家的KML矢量数据分析分享给大家,如果你需要这些数据,请在文末查看领取方式。 世界上横跨两大洲的国家 地球被分为七个大洲分别是亚洲、欧洲、北美洲、南美洲、非洲、大洋洲和南极洲。 七大洲示意图 其中,南极洲是无人居住的大陆,而其他六个大洲则孕育了众多国家和

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo