p5.js实现故宫橘猫赏秋图动画


Posted in Javascript onOctober 23, 2019

用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=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个点,然后画三角形,形成一个没有四肢,没有尾巴的橘猫。

p5.js实现故宫橘猫赏秋图动画

尾巴用了贝塞尔曲线,坐标也跟中心点关联。

猫的四肢是运动视觉的关键!!!动画之所以能动是因为有承上启下的连续性动作。猫行走从侧面看过去就是两腿相互交叉变换。所以在写动画逻辑之前你需要先画出关键帧状态。
关键帧状态确定了就可开始着手动画逻辑:首先视觉上我们先要营造出猫在原地踏步的感觉。我们有两个关键帧状态,所以可以运用模运算,在运动的中心坐标基础上模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);
 }
 }

至此,动画完成。

手绘与码绘的对比

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

发现的问题

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
CSS+JS构建的图片查看器
Jul 22 Javascript
如何将php数组或者对象传递给javascript
Mar 20 Javascript
Js Jquery创建一个弹出层可加载一个页面
May 08 Javascript
浅谈JS日期(Date)处理函数
Dec 07 Javascript
javascript中字体浮动效果的简单实例演示
Nov 18 Javascript
JavaScript实现图片滑动切换的代码示例分享
Mar 06 Javascript
使用jquery提交form表单并自定义action的方法
May 25 Javascript
详解支持Angular 2的表格控件
Jan 19 Javascript
swiper动态改变滑动内容的实现方法
Jan 17 Javascript
TypeScript开发Node.js程序的方法
Apr 30 Javascript
原生JS实现汇率转换功能代码实例
May 13 Javascript
es5 类与es6中class的区别小结
Nov 09 Javascript
vue父组件给子组件的组件传值provide inject的方法
Oct 23 #Javascript
p5.js临摹旋转爱心
Oct 23 #Javascript
JavaScript 作用域scope简单汇总
Oct 23 #Javascript
node.js使用fs读取文件出错的解决方案
Oct 23 #Javascript
jquery 键盘事件 keypress() keydown() keyup()用法总结
Oct 23 #jQuery
JavaScript提升机制Hoisting详解
Oct 23 #Javascript
使用p5.js实现动态GIF图片临摹重现
Oct 23 #Javascript
You might like
ThinkPHP使用心得分享-上传类UploadFile的使用
2014/05/15 PHP
Session 失效的原因汇总及解决丢失办法
2015/09/30 PHP
php文件上传、下载和删除示例
2020/08/28 PHP
yii2.0整合阿里云oss上传单个文件的示例
2017/09/19 PHP
通过实例解析PHP数据类型转换方法
2020/07/11 PHP
JavaScript和JQuery实用代码片段(一)
2010/04/07 Javascript
jQuery Select(单选) 模拟插件 V1.3.62 改进版
2010/07/17 Javascript
Node.js实现简单聊天服务器
2014/06/20 Javascript
js获取页面传来参数的方法
2014/09/06 Javascript
jquery取子节点及当前节点属性值的方法
2014/09/09 Javascript
有关json_decode乱码及NULL的问题
2015/10/13 Javascript
快速学习JavaScript的6个思维技巧
2015/10/13 Javascript
jQuery插件dataTables添加序号列的方法
2016/07/06 Javascript
vue.js入门教程之绑定class和style样式
2016/09/02 Javascript
JS实现的文字间歇循环滚动效果完整示例
2018/02/13 Javascript
小程序测试后台服务的方法(ngrok)
2019/03/08 Javascript
jQuery 查找元素操作实例小结
2019/10/02 jQuery
Ant Design Vue 添加区分中英文的长度校验功能
2020/01/21 Javascript
Vue router安装及使用方法解析
2020/12/02 Vue.js
浅谈Python中的作用域规则和闭包
2018/03/20 Python
解决Python requests库编码 socks5代理的问题
2018/05/07 Python
Python字符串匹配之6种方法的使用详解
2019/04/08 Python
用python打印菱形的实操方法和代码
2019/06/25 Python
Python 多个图同时在不同窗口显示的实现方法
2019/07/07 Python
python双向链表原理与实现方法详解
2019/12/03 Python
pycharm双击无响应(打不开问题解决办法)
2020/01/10 Python
HTML5: Web 标准最巨大的飞跃
2008/10/17 HTML / CSS
html5 初试 indexedDB(推荐)
2016/07/21 HTML / CSS
size?爱尔兰官方网站:英国伦敦的球鞋精品店
2019/03/31 全球购物
Timberland法国官网:购买靴子、鞋子、衣服、夹克和配饰
2019/11/30 全球购物
超市营业员求职简历的自我评价
2013/10/17 职场文书
致共产党员倡议书
2014/04/16 职场文书
门面房租房协议书
2014/12/01 职场文书
青少年法制教育心得体会
2016/01/14 职场文书
《珍珠鸟》教学反思
2016/02/16 职场文书
SQL Server携程核心系统无感迁移到MySQL实战
2022/06/01 SQL Server