這篇文章給大家分享的是有關p5.js如何實現故宮橘貓賞秋圖動畫的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
用p5.js實現一個小動畫——故宮橘貓賞秋圖
互動媒體第二次作業要求我們手繪一幅動畫,再用代碼實現出動畫。由于時間原因,手繪并沒有畫動畫,而是以插畫的形式畫了一張,然后p5實現了動畫。
這里先放效果圖:
板繪插圖

碼繪效果圖

這里強烈建議直接運行代碼?。?!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=color(180,180,150,0.5*255);
function setup() {
createCanvas(Width,Height);
}
function draw() {
frameRate(5);
drawwall();
drawsky();
push();
translate(10,-5);
YinxingTree();
pop();
draw_wallshadow();
if(center_x<-10)
center_x=650;
center_x-=15*easing;
drawcat(cat_scale,center_x,center_y);
translate(10,-25);
noStroke();
fill(30);
rect(Width-10,0,200,Height);
push();
YinxingTree();
pop();
}
function drawcat(cat_scale,center_x,center_y)
{
stroke(200,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;
fill(220,200,180);
triangle(center_x,center_y,pos1_x,pos1_y,pos2_x,pos2_y);
triangle(center_x,center_y,pos1_x,pos1_y,pos3_x,pos3_y);
fill(150,70,10);
triangle(center_x,center_y,pos3_x,pos3_y,pos4_x,pos4_y);
triangle(pos3_x,pos3_y,pos4_x,pos4_y,pos5_x,pos5_y);
triangle(pos3_x,pos3_y,pos5_x,pos5_y,pos6_x,pos6_y);
fill(150,70,10);
triangle(pos3_x,pos3_y,pos7_x,pos7_y,pos8_x,pos8_y);
fill(180,100,10);
triangle(pos8_x,pos8_y,pos9_x,pos9_y,pos5_x,pos5_y);
fill(150,70,10);
triangle(center_x,center_y,pos2_x,pos2_y,pos10_x,pos10_y);
triangle(pos2_x,pos2_y,pos10_x,pos10_y,pos11_x,pos11_y);
fill(180);
feetControl(pos1_x-6,pos1_y);
feetControl(pos2_x-4,pos2_y);
noFill();
weiba(pos11_x,pos11_y);
}
function weiba(x,y)
{
push();
strokeWeight(10);
stroke(150,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;
bezier(x1,y1,x2,y2,x3,y3,x4,y4);
noStroke();
pop();
}
function feetControl(x,y)
{
if(x%2==0)
{
rect(x-(cat_scale)/10,y-8,(cat_scale)/10,(cat_scale)*1/3+8);
}
else
{
quad(x,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);
quad(x,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 segment(trans_x, trans_y, a,segLength) {
push();
translate(trans_x, trans_y);
rotate(a);
rect();
pop();
}
function draw_wallshadow()
{
noStroke();
var c1=color(160,10,0);
var c2=color(80,10,80);
setGradient(0,600,Width,150,c1,c2,1);
noStroke();
fill(160,10,0);
for(var i=0;i<Width;i++)
{
arc(i,600,50,15,PI,0);
i=i+80;
}
}
function drawwall()
{
noStroke();
fill(100,10,0);
rect(0, 0, Width, Height);
fill(190,70,20);
rect(0, Height-wall_Height, wall_Width, wall_Height);
drawWuYan1();
drawWuYan2();
drawWuYan3();
drawWuYan4();
}
function drawWuYan1()
{
stroke(20);
fill(190,100,10);
for(var i=0;i<Width;i++)
{
rect(i-5,wall_Height+70,wuyan_width,wuyan_height);
i=i+wuyan_width;
}
}
function drawWuYan2()
{
var cwu2_1=color(50,120,30);
var cwu2_2=color(60,10,0);
for(var j=0;j<Width+80;j++)
{
setGradient(j-65,wall_Height+35,
wuyan_width,wuyan_height+10,
cwu2_1,cwu2_2,1);
stroke(180,130,20);
rect(j-65,wall_Height+36,
wuyan_width,wuyan_height+10);
j=j+wuyan_width;
}
var cwu3_1=color(10,20,10);
var cwu3_2=color(80,100,20);
fill(50,120,30);
setGradient(0,wall_Height-15,
Width,50,cwu3_1,cwu3_2,1);
}
function drawWuYan3()
{
noStroke();
fill(190,150,90);
for(var k=0;k<Width;k++)
{
rect(k,skyHeight,wuyan_width,10);
k=k+wuyan_width;
}
fill(190,100,10);
rect(0,skyHeight+15,Width,12);
fill(190,110,30);
rect(0,skyHeight+35,Width,35);
}
function drawPIdwon(x_trans)
{
stroke(90,50,50);
push();
translate(x_trans, skyHeight+100);
rotate(0.0);
fill(140,100,50);
arc(0, 0, quad_width, quad_width-15, 0, PI);
pop();
}
function drawPIdwon_shadow(x_trans,shadow)
{
noStroke();
push();
translate(x_trans, skyHeight+100);
rotate(0.0);
fill(10,20,10);
arc(0, 0, quad_width+shadow, quad_width+shadow, 0, PI);
pop();
}
function drawquad(i,j,x_trans)
{
var c1=color(90,50,50);
var c2=color(180,90,50);
setGradient(x_trans-(quad_width/2)+i,
skyHeight+93-j,
quad_width,5,c1,c2,2);
}
function drawCicle(x_trans,angle,c1,c2,c3,i)
{
push();
noStroke();
fill(c1,c2,c3);
translate(x_trans-i+7,skyHeight+70+i*3);
rotate(angle);
arc(0,0,50,50, 0, PI/2);
pop();
}
function drawCicle_all(x_trans)
{
for(var i=0;i<8;i++)
{
drawCicle(x_trans+quad_width-8,24.5,100,10,10,i);
drawCicle(x_trans+quad_width-8,-2.2,130,110,90,i);
drawCicle(x_trans+quad_width-8,1,70,20,10,i);
drawCicle(x_trans+quad_width-8,-3.5,200,160,80,i);
}
stroke(50,10,10);
fill(140,100,50);
ellipse(x_trans+60,skyHeight+95,50,50);
fill(80,60,20);
ellipse(x_trans+60,skyHeight+95,35,35);
}
function drawWuYan4()
{
for(var x_trans=50;x_trans<Width;x_trans++)
{
drawPIdwon_shadow(x_trans+10,10);
drawPIdwon(x_trans);
for(var i=0;i<5;i++)
{
yp=i*5;
drawquad(i,yp,x_trans);
}
drawCicle_all(x_trans);
x_trans=x_trans+120;
}
}
function YinxingTree()
{
push();
drawtree(220,180,0,-20,20,random(0.6));
drawtree(120,60,0,-100,100,random(0.01));
drawtree(120,60,0,-50,160,random(0.01));
drawtree(180,160,0,40,160,random(0.05));
drawtree(200,100,0,-20,100,random(1));
drawtree(200,160,0,0,120,random(0.5));
drawtree(220,160,0,55,160,random(0.1));
drawtree(240,200,0,50,100,random(0.3));
drawtree(240,200,0,50,180,random(0.3));
drawtree(240,200,0,80,190,random(1));
drawtree(220,180,0,-50,80,random(0.1));
translate(150,90);
drawtree(220,180,0,-50,150,random(0.5));
translate(-100,-150);
drawtree(240,200,120,-100,100,random(0.01));
pop();
}
function drawtree(c1,c2,c3,pos_x,pos_y,pos_angle)
{
push();
rotate(pos_angle);
var trans_x;
var trans_y;
var trans_angle;
fill(c1,c2,c3);
for(var i=0;i<20;i++)
{
trans_x=random(50);
trans_y=random(20);
trans_angle=random(-0.5);
push();
translate(trans_x,trans_y);
rotate(trans_angle);
drawYinXing(pos_x,pos_y);
pop();
}
pop();
}
function drawYinXing(pos_x,pos_y)
{
stroke(200,150,60);
push();
translate(pos_x, pos_y);
rotate(0.0);
arc(0, 0, 30, 30, 0, PI/2);
pop();
}
function drawsky()
{
var c1 = color(90,150,205);
var c2 = color(190,200,220);
noStroke();
setGradient(0, 0, Width, skyHeight,c1,c2,1);
}
function setGradient(x, y, w, h, c1, c2,axis)
{
noFill();
if (axis == Y_AXIS) { // Top to bottom gradient
for (var i = y; i <= y+h; i++) {
var inter = map(i, y, y+h, 0, 1);
var c = lerpColor(c1, c2, inter);
stroke(c);
line(x, i, x+w, i);
}
}
else if (axis == X_AXIS) { // Left to right gradient
for (var k = x; k <= x+w; k++) {
var interk = map(k, x, x+w, 0, 1);
var ck = lerpColor(c1, c2, interk);
stroke(ck);
line(k, y, k, y+h);
}
}
}代碼結構解析
1.背景:
其實畫背景還挺簡單的,基本物體就是紅墻,屋檐,銀杏樹,天空。
天空是漸變的,用了一個函數,p5官網里面也有:
function drawsky()
{
var c1 = color(90,150,205);
var c2 = color(190,200,220);
noStroke();
setGradient(0, 0, Width, skyHeight,c1,c2,1);
}
function setGradient(x, y, w, h, c1, c2,axis)
{
noFill();
if (axis == Y_AXIS) { // Top to bottom gradient
for (var i = y; i <= y+h; i++) {
var inter = map(i, y, y+h, 0, 1);
var c = lerpColor(c1, c2, inter);
stroke(c);
line(x, i, x+w, i);
}
}
else if (axis == X_AXIS) { // Left to right gradient
for (var k = x; k <= x+w; k++) {
var interk = map(k, x, x+w, 0, 1);
var ck = lerpColor(c1, c2, interk);
stroke(ck);
line(k, y, k, y+h);
}
}
}紅墻就不細說了,直接看屋檐,屋檐還稍微有點東西。觀察故宮屋檐結構之后發現,故宮這樣的建筑簡直太有規律可循了!你只要生成一個基本元,接下來的就只用循環生成就可以。我們主要來看看圓木那一塊怎么實現。
圓木那里其實還挺麻煩,主要是有光的影響,圓木被分為三個面:受光面,反光面,陰影面,直接用一個圓肯定解決不了,我想了一個辦法,用三個扇形就可以區分三個面。
具體代碼:
function drawCicle(x_trans,angle,c1,c2,c3,i)
{
push();
noStroke();
fill(c1,c2,c3);
translate(x_trans-i+7,skyHeight+70+i*3);
rotate(angle);
arc(0,0,50,50, 0, PI/2);
pop();
}
function drawCicle_all(x_trans)
{
for(var i=0;i<8;i++)
{
drawCicle(x_trans+quad_width-8,24.5,100,10,10,i);
drawCicle(x_trans+quad_width-8,-2.2,130,110,90,i);
drawCicle(x_trans+quad_width-8,1,70,20,10,i);
drawCicle(x_trans+quad_width-8,-3.5,200,160,80,i);
}
stroke(50,10,10);
fill(140,100,50);
ellipse(x_trans+60,skyHeight+95,50,50);
fill(80,60,20);
ellipse(x_trans+60,skyHeight+95,35,35);
}還有瓦片上的陰影,也用了漸變過渡,這里就不貼代碼了。
銀杏樹
一開始對銀杏樹沒什么頭緒,觀察了好幾棵學校里的銀杏,在大風刮過之時,金黃樹葉在風中顫抖搖晃,我突然有了靈感——色塊堆積。我可以不用準準確確的畫出這棵樹長啥樣,我只需要保證它在運動中是符合這棵樹的邏輯的,那么這棵樹就是成功的。
下面貼上代碼:
function YinxingTree()
{
push();
drawtree(220,180,0,-20,20,random(0.6));
drawtree(120,60,0,-100,100,random(0.01));
drawtree(120,60,0,-50,160,random(0.01));
drawtree(180,160,0,40,160,random(0.05));
drawtree(200,100,0,-20,100,random(1));
drawtree(200,160,0,0,120,random(0.5));
drawtree(220,160,0,55,160,random(0.1));
drawtree(240,200,0,50,100,random(0.3));
drawtree(240,200,0,50,180,random(0.3));
drawtree(240,200,0,80,190,random(1));
drawtree(220,180,0,-50,80,random(0.1));
translate(150,90);
drawtree(220,180,0,-50,150,random(0.5));
translate(-100,-150);
drawtree(240,200,120,-100,100,random(0.01));
pop();
}
function drawtree(c1,c2,c3,pos_x,pos_y,pos_angle)
{
push();
rotate(pos_angle);
var trans_x;
var trans_y;
var trans_angle;
fill(c1,c2,c3);
for(var i=0;i<20;i++)
{
trans_x=random(50);
trans_y=random(20);
trans_angle=random(-0.5);
push();
translate(trans_x,trans_y);
rotate(trans_angle);
drawYinXing(pos_x,pos_y);
pop();
}
pop();
}
function drawYinXing(pos_x,pos_y)
{
stroke(200,150,60);
push();
translate(pos_x, pos_y);
rotate(0.0);
arc(0, 0, 30, 30, 0, PI/2);
pop();
}大量使用radom可以讓這棵樹更自然。
2.動畫主角——貓
這里我先對貓進行了一些處理——低多邊形處理。
吸取了第一個實驗的教訓,這次我先設置了一個中心點,然后在根據這個點擴充出有關貓的肢干總共12個點,然后畫三角形,形成一個沒有四肢,沒有尾巴的橘貓。

尾巴用了貝塞爾曲線,坐標也跟中心點關聯。
貓的四肢是運動視覺的關鍵?。?!動畫之所以能動是因為有承上啟下的連續性動作。貓行走從側面看過去就是兩腿相互交叉變換。所以在寫動畫邏輯之前你需要先畫出關鍵幀狀態。
關鍵幀狀態確定了就可開始著手動畫邏輯:首先視覺上我們先要營造出貓在原地踏步的感覺。我們有兩個關鍵幀狀態,所以可以運用模運算,在運動的中心坐標基礎上模2,結果對應兩個狀態。
附上代碼:
function feetControl(x,y)
{
if(x%2==0)
{
rect(x-(cat_scale)/10,y-8,(cat_scale)/10,(cat_scale)*1/3+8);
}
else
{
quad(x,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);
quad(x,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);
}
}至此,動畫完成。
手繪與碼繪的對比
在動畫這個應用上,其實兩者各有千秋。手繪能做到畫面更加精致有更多細節,更能體現質感,但同時,它又太過費時。而碼繪在運動這一方面有著得天獨厚的優勢,它能更平滑的完成動畫操作。
發現的問題
碼繪在建立場景的過程中,發現對于環境色這一概念,幾乎還是一個空白領域。
感謝各位的閱讀!關于“p5.js如何實現故宮橘貓賞秋圖動畫”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。