宝塔服务器面板,一键全能部署及管理,送你10850元礼包,点我领取

用p5.js实现一个小动画——故宫橘猫赏秋图

互动媒体第二次作业要求我们手绘一幅动画,再用代码实现出动画。由于时间原因,手绘并没有画动画,而是以插画的形式画了一张,然后p5实现了动画。
这里先放效果图:

板绘插图

用p5.js实现一个小动画——故宫橘猫赏秋图-风君子博客

码绘效果图

用p5.js实现一个小动画——故宫橘猫赏秋图-风君子博客
这里强烈建议直接运行代码!!!gif丢帧!!!可怜我的渐变啊啊啊啊!!!
下面附上完整代码:

var Width=600;
var Height=700;
var pixel=1;var Y_AXIS = 1;
var X_AXIS = 2;var skyHeight=190;
var wall_Width=600;
var wall_Height=300;
var wuyan_width=120;
var wuyan_height=20;
var quad_width=70;
var quad_height=30;
var center_x=500;
var center_y=115;
var cat_scale=111;var easing=1; var Time;//face_color=color180,180,150,0.5*255);
function setup) {createCanvasWidth,Height); }function draw) { frameRate5);drawwall);  drawsky);push);translate10,-5);YinxingTree);pop);draw_wallshadow);ifcenter_x<-10)center_x=650;center_x-=15*easing;drawcatcat_scale,center_x,center_y);translate10,-25);noStroke);fill30);rectWidth-10,0,200,Height);push);YinxingTree);pop);}function drawcatcat_scale,center_x,center_y){stroke200,200,240);noStroke);//肚子pos1_x=center_x-cat_scale)/3;pos1_y=center_y+cat_scale)*2/5-5;pos2_x=center_x+cat_scale*1/3);pos2_y=center_y+cat_scale)*2/5;//前体pos3_x=pos1_x-cat_scale/5);pos3_y=center_y+cat_scale)*2/5;pos4_x=pos1_x-cat_scale/8);pos4_y=center_y+cat_scale)/15;pos5_x=pos4_x-cat_scale/8);pos5_y=pos4_y-cat_scale)/20;//头pos6_x=pos5_x-cat_scale/4);pos6_y=pos5_y-cat_scale)/6;pos7_x=pos5_x-cat_scale/6);pos7_y=pos5_y-cat_scale)/30;pos8_x=pos5_x-cat_scale)*3/8;pos8_y=pos5_y+cat_scale)/8;pos9_x=pos8_x+cat_scale)/5;pos9_y=pos8_y+cat_scale)/5;//屁股pos10_x=pos2_x-cat_scale/4)*0;pos10_y=pos2_y-cat_scale)*1/3;pos11_x=pos10_x+cat_scale*1/8);pos11_y=pos10_y+cat_scale)/10;fill220,200,180);trianglecenter_x,center_y,pos1_x,pos1_y,pos2_x,pos2_y);trianglecenter_x,center_y,pos1_x,pos1_y,pos3_x,pos3_y);fill150,70,10);trianglecenter_x,center_y,pos3_x,pos3_y,pos4_x,pos4_y);trianglepos3_x,pos3_y,pos4_x,pos4_y,pos5_x,pos5_y);trianglepos3_x,pos3_y,pos5_x,pos5_y,pos6_x,pos6_y);fill150,70,10);trianglepos3_x,pos3_y,pos7_x,pos7_y,pos8_x,pos8_y);fill180,100,10);trianglepos8_x,pos8_y,pos9_x,pos9_y,pos5_x,pos5_y);fill150,70,10);trianglecenter_x,center_y,pos2_x,pos2_y,pos10_x,pos10_y);trianglepos2_x,pos2_y,pos10_x,pos10_y,pos11_x,pos11_y);fill180);feetControlpos1_x-6,pos1_y);feetControlpos2_x-4,pos2_y);noFill);weibapos11_x,pos11_y);}function weibax,y){push);strokeWeight10);stroke150,70,10);x1=x-20;y1=y;x2=x+20;y2=y-20;x3=x+25;y3=y+5;x4=x+55;y4=y-20;bezierx1,y1,x2,y2,x3,y3,x4,y4);noStroke);pop);}function feetControlx,y){ifx%2==0){rectx-cat_scale)/10,y-8,cat_scale)/10,cat_scale)*1/3+8);    }else{quadx,y-10,x-cat_scale)/10,y-10,x-cat_scale)/10+cat_scale/10),y+cat_scale)*1/3,x+cat_scale/10),y+cat_scale)*1/3);quadx,y-15,x-cat_scale)/10,y-15,x-cat_scale)/10-cat_scale/5),y+cat_scale)*1/3,x-cat_scale/5),y+cat_scale)*1/3);}}function segmenttrans_x, trans_y, a,segLength) {push);translatetrans_x, trans_y);rotatea);rect);pop);}function draw_wallshadow){noStroke);var c1=color160,10,0);var c2=color80,10,80);setGradient0,600,Width,150,c1,c2,1);noStroke);fill160,10,0);forvar i=0;i<Width;i++){arci,600,50,15,PI,0);i=i+80;}}function drawwall){noStroke);fill100,10,0);rect0, 0, Width, Height);fill190,70,20);rect0, Height-wall_Height, wall_Width, wall_Height);drawWuYan1);   drawWuYan2); drawWuYan3);drawWuYan4);}function drawWuYan1){stroke20);fill190,100,10);forvar i=0;i<Width;i++){recti-5,wall_Height+70,wuyan_width,wuyan_height);i=i+wuyan_width;} }function drawWuYan2){var cwu2_1=color50,120,30);var cwu2_2=color60,10,0);forvar j=0;j<Width+80;j++){setGradientj-65,wall_Height+35,wuyan_width,wuyan_height+10,cwu2_1,cwu2_2,1);stroke180,130,20);rectj-65,wall_Height+36,wuyan_width,wuyan_height+10);j=j+wuyan_width;} var cwu3_1=color10,20,10);var cwu3_2=color80,100,20);fill50,120,30);setGradient0,wall_Height-15,Width,50,cwu3_1,cwu3_2,1);}function drawWuYan3){noStroke);fill190,150,90);forvar k=0;k<Width;k++){rectk,skyHeight,wuyan_width,10);k=k+wuyan_width;}fill190,100,10);rect0,skyHeight+15,Width,12);fill190,110,30);rect0,skyHeight+35,Width,35);}function drawPIdwonx_trans){stroke90,50,50);push);translatex_trans, skyHeight+100);rotate0.0);fill140,100,50);arc0, 0, quad_width, quad_width-15, 0, PI);pop);}function drawPIdwon_shadowx_trans,shadow){noStroke);push);translatex_trans, skyHeight+100);rotate0.0);fill10,20,10);arc0, 0, quad_width+shadow, quad_width+shadow, 0, PI);pop);}function drawquadi,j,x_trans){var c1=color90,50,50);var c2=color180,90,50);setGradientx_trans-quad_width/2)+i, skyHeight+93-j,quad_width,5,c1,c2,2);}function drawCiclex_trans,angle,c1,c2,c3,i)
{push);noStroke);fillc1,c2,c3);translatex_trans-i+7,skyHeight+70+i*3);rotateangle);arc0,0,50,50, 0, PI/2);pop);
}function drawCicle_allx_trans)
{forvar i=0;i<8;i++){drawCiclex_trans+quad_width-8,24.5,100,10,10,i);drawCiclex_trans+quad_width-8,-2.2,130,110,90,i);drawCiclex_trans+quad_width-8,1,70,20,10,i);drawCiclex_trans+quad_width-8,-3.5,200,160,80,i);}stroke50,10,10);fill140,100,50);ellipsex_trans+60,skyHeight+95,50,50);fill80,60,20);ellipsex_trans+60,skyHeight+95,35,35);
}function drawWuYan4)
{forvar x_trans=50;x_trans<Width;x_trans++){drawPIdwon_shadowx_trans+10,10);drawPIdwonx_trans);forvar i=0;i<5;i++){yp=i*5;drawquadi,yp,x_trans);}drawCicle_allx_trans);x_trans=x_trans+120;}}function YinxingTree)
{push);drawtree220,180,0,-20,20,random0.6));drawtree120,60,0,-100,100,random0.01));drawtree120,60,0,-50,160,random0.01));drawtree180,160,0,40,160,random0.05));drawtree200,100,0,-20,100,random1));drawtree200,160,0,0,120,random0.5));drawtree220,160,0,55,160,random0.1));drawtree240,200,0,50,100,random0.3));drawtree240,200,0,50,180,random0.3));drawtree240,200,0,80,190,random1));drawtree220,180,0,-50,80,random0.1));translate150,90);drawtree220,180,0,-50,150,random0.5));translate-100,-150);drawtree240,200,120,-100,100,random0.01));pop);
}function drawtreec1,c2,c3,pos_x,pos_y,pos_angle)
{push);rotatepos_angle);var trans_x;var trans_y;var trans_angle;fillc1,c2,c3);forvar i=0;i<20;i++){trans_x=random50);trans_y=random20);trans_angle=random-0.5);push);translatetrans_x,trans_y);rotatetrans_angle);drawYinXingpos_x,pos_y);pop);}pop);}function drawYinXingpos_x,pos_y){stroke200,150,60);push);translatepos_x, pos_y);rotate0.0);arc0, 0, 30, 30, 0, PI/2);pop);}function drawsky){var c1 = color90,150,205);var c2 = color190,200,220);noStroke);setGradient0, 0, Width, skyHeight,c1,c2,1);}function setGradientx, y, w, h, c1, c2,axis) {noFill);if axis == Y_AXIS) {  // Top to bottom gradientfor var i = y; i <= y+h; i++) {var inter = mapi, y, y+h, 0, 1);var c = lerpColorc1, c2, inter);strokec);linex, i, x+w, i);}}  else if axis == X_AXIS) {  // Left to right gradientfor var k = x; k <= x+w; k++) {var interk = mapk, x, x+w, 0, 1);var ck = lerpColorc1, c2, interk);strokeck);linek, y, k, y+h);}}}
代码结构解析

1.背景:
其实画背景还挺简单的,基本物体就是红墙,屋檐,银杏树,天空。
天空是渐变的,用了一个函数,p5官网里面也有:

function drawsky){var c1 = color90,150,205);var c2 = color190,200,220);noStroke);setGradient0, 0, Width, skyHeight,c1,c2,1);}function setGradientx, y, w, h, c1, c2,axis) {noFill);if axis == Y_AXIS) {  // Top to bottom gradientfor var i = y; i <= y+h; i++) {var inter = mapi, y, y+h, 0, 1);var c = lerpColorc1, c2, inter);strokec);linex, i, x+w, i);}}  else if axis == X_AXIS) {  // Left to right gradientfor var k = x; k <= x+w; k++) {var interk = mapk, x, x+w, 0, 1);var ck = lerpColorc1, c2, interk);strokeck);linek, y, k, y+h);}}}

红墙就不细说了,直接看屋檐,屋檐还稍微有点东西。观察故宫屋檐结构之后发现,故宫这样的建筑简直太有规律可循了!你只要生成一个基本元,接下来的就只用循环生成就可以。我们主要来看看圆木那一块怎么实现。
圆木那里其实还挺麻烦,主要是有光的影响,圆木被分为三个面:受光面,反光面,阴影面,直接用一个圆肯定解决不了,我想了一个办法,用三个扇形就可以区分三个面。
具体代码:

function drawCiclex_trans,angle,c1,c2,c3,i)
{push);noStroke);fillc1,c2,c3);translatex_trans-i+7,skyHeight+70+i*3);rotateangle);arc0,0,50,50, 0, PI/2);pop);
}function drawCicle_allx_trans)
{forvar i=0;i<8;i++){drawCiclex_trans+quad_width-8,24.5,100,10,10,i);drawCiclex_trans+quad_width-8,-2.2,130,110,90,i);drawCiclex_trans+quad_width-8,1,70,20,10,i);drawCiclex_trans+quad_width-8,-3.5,200,160,80,i);}stroke50,10,10);fill140,100,50);ellipsex_trans+60,skyHeight+95,50,50);fill80,60,20);ellipsex_trans+60,skyHeight+95,35,35);
}

还有瓦片上的阴影,也用了渐变过渡,这里就不贴代码了。

银杏树
一开始对银杏树没什么头绪,观察了好几棵学校里的银杏,在大风刮过之时,金黄树叶在风中颤抖摇晃,我突然有了灵感——色块堆积。我可以不用准准确确的画出这棵树长啥样,我只需要保证它在运动中是符合这棵树的逻辑的,那么这棵树就是成功的。
下面贴上代码:

function YinxingTree)
{push);drawtree220,180,0,-20,20,random0.6));drawtree120,60,0,-100,100,random0.01));drawtree120,60,0,-50,160,random0.01));drawtree180,160,0,40,160,random0.05));drawtree200,100,0,-20,100,random1));drawtree200,160,0,0,120,random0.5));drawtree220,160,0,55,160,random0.1));drawtree240,200,0,50,100,random0.3));drawtree240,200,0,50,180,random0.3));drawtree240,200,0,80,190,random1));drawtree220,180,0,-50,80,random0.1));translate150,90);drawtree220,180,0,-50,150,random0.5));translate-100,-150);drawtree240,200,120,-100,100,random0.01));pop);
}function drawtreec1,c2,c3,pos_x,pos_y,pos_angle)
{push);rotatepos_angle);var trans_x;var trans_y;var trans_angle;fillc1,c2,c3);forvar i=0;i<20;i++){trans_x=random50);trans_y=random20);trans_angle=random-0.5);push);translatetrans_x,trans_y);rotatetrans_angle);drawYinXingpos_x,pos_y);pop);}pop);}function drawYinXingpos_x,pos_y){stroke200,150,60);push);translatepos_x, pos_y);rotate0.0);arc0, 0, 30, 30, 0, PI/2);pop);}

大量使用radom可以让这棵树更自然。

2.动画主角——猫
这里我先对猫进行了一些处理——低多边形处理。
吸取了第一个实验的教训,这次我先设置了一个中心点,然后在根据这个点扩充出有关猫的肢干总共12个点,然后画三角形,形成一个没有四肢,没有尾巴的橘猫。
用p5.js实现一个小动画——故宫橘猫赏秋图-风君子博客
尾巴用了贝塞尔曲线,坐标也跟中心点关联。
猫的四肢是运动视觉的关键!!!动画之所以能动是因为有承上启下的连续性动作。猫行走从侧面看过去就是两腿相互交叉变换。所以在写动画逻辑之前你需要先画出关键帧状态。
关键帧状态确定了就可开始着手动画逻辑:首先视觉上我们先要营造出猫在原地踏步的感觉。我们有两个关键帧状态,所以可以运用模运算,在运动的中心坐标基础上模2,结果对应两个状态。
附上代码:

function feetControlx,y){ifx%2==0){rectx-cat_scale)/10,y-8,cat_scale)/10,cat_scale)*1/3+8);    }else{quadx,y-10,x-cat_scale)/10,y-10,x-cat_scale)/10+cat_scale/10),y+cat_scale)*1/3,x+cat_scale/10),y+cat_scale)*1/3);quadx,y-15,x-cat_scale)/10,y-15,x-cat_scale)/10-cat_scale/5),y+cat_scale)*1/3,x-cat_scale/5),y+cat_scale)*1/3);}}

至此,动画完成。

手绘与码绘的对比

在动画这个应用上,其实两者各有千秋。手绘能做到画面更加精致有更多细节,更能体现质感,但同时,它又太过费时。而码绘在运动这一方面有着得天独厚的优势,它能更平滑的完成动画操作。

发现的问题

码绘在建立场景的过程中,发现对于环境色这一概念,几乎还是一个空白领域。