总体概览
1.设计理念
2.设计步骤
3.设计效果展示
一、设计理念
我对于自画像的理解,不只停留在当前画像上的理解。人的一生经历过很多很多特殊的时期,也有着每个时期的特色,因此我的设计将我以前的时光中一些具有特殊意义的时期的画像也囊括了进来,其中由于画人像比较复杂,有些部分以其他部件代替。
二、设计步骤
(1)童年时期的设计:奶瓶+婴儿
奶瓶的绘制:
- 思考奶瓶的各个部分的元素:从而为建立奶瓶类做准备。我们先参考一下市面上的奶瓶:
通过观察我们发现,奶瓶的绘制可以使用基础图形实现,其中包括线、圆角矩形、椭圆等等。
- 圆角矩形的画法:
<1>在屏幕上绘制一个矩形。长方形是四边的形状,每个角都是九十度。默认情况下,前两个参数设置左上角的位置,第三个参数设置宽度,第四个参数设置高度。但是,可以使用rectMode()函数更改这些参数的解释方式。
<2>要绘制圆角矩形,需要添加第五个参数,该参数用作所有四个角的半径值。
<3>要为每个角使用不同的半径值,需要包含八个参数。当使用8个参数时,后4个参数分别设置每个角的圆弧半径,从左上角开始,沿矩形顺时针移动。
- 构建奶瓶类:
在绘制奶瓶时,其中奶瓶类有个属性是奶瓶绘制的位置坐标x,y。这个x,y在这里我设定的是瓶身左上角的坐标值。要注意:矩形绘制的时候是有很多模式设置的,模式的不同,决定矩形绘制的位置的不同。同时,还应该注意使用类时,使用相对位置来表示,不要设置绝对的数值,那样会造成可变性弱。
class FeedingBottle {
private float x;
private float y;
private float w;//the width
private float h;//the hight of the center bottle body
private color c1;//the color of the bottle
private color c2;
private color c3;
private color c4;
private color lineColor=color(164, 169, 172);
private float bottleHight;
private float bottleWidth;
public FeedingBottle() {
this.x=0;
this.y=0;
this.w=0;
this.h=0;
this.c1=color(0, 0, 0);
this.c2=color(0, 0, 0);
this.c3=color(0, 0, 0);
this.c4=color(0, 0, 0);
}
public FeedingBottle(float x, float y, float w, float h, color c1, color c2, color c3, color c4) {
this.x=x;
this.y=y;
this.w=w;
this.h=h;
this.c1=c1;
this.c2=c2;
this.c3=c3;
this.c4=c4;
this.bottleHight=this.h;
this.bottleWidth=this.w;
}
public void setLineColor(color line) {
this.lineColor=line;
}
public void setScale(float scale) {
this.w=bottleWidth*scale;
this.h=bottleHight*scale;
}
public void setColor1(color c1) {
this.c1=c1;
}
public void setColor2(color c2) {
this.c2=c2;
}
public void setColor3(color c3) {
this.c3=c3;
}
public void setColor4(color c4) {
this.c4=c4;
}
public void drawBottleBody() {
fill(c1);
rect(x, y, w, h, 10);
//draw line
float bottoleHeight=this.y;
for (; bottoleHeight<y+h-h/6; bottoleHeight+=h/7) {
line(x, bottoleHeight, x+w/3, bottoleHeight);
}
}
public void drawLid() {
fill(c2);
rect(x, y-h/6, w, h/6, 10);
}
public void drawFeedingMouse() {
fill(c4);
ellipse(x+w/2, y-h/3, w/3, h/3);
fill(c3);
rect(x+w/6, y-h/3, 2*w/3, h/4, 20);
}
public void drawAllBottle() {
stroke(lineColor);
this.drawFeedingMouse();
this.drawBottleBody();
this.drawLid();
}
}
- 绘制的奶瓶的展示
婴儿的绘制
小时候我,比较圆圆润润,白白净净,因此在这里,我给自己设定的形象是圆滚滚可爱的样子。同时将刚刚的绘制的奶瓶放在了我绘制的小时候的自己的手中~~~~在这里,由于涉及到很多曲线,因此打算使用Bezier曲线来绘制。
- Bezier曲线的介绍
贝塞尔曲线就是这样的一条曲线,它是依据四个位置任意的点坐标绘制出的一条光滑曲线。在历史上,研究贝塞尔曲线的人最初是按照已知曲线参数方程来确定四个点的思路设计出这种矢量曲线绘制法。贝塞尔曲线的有趣之处更在于它的“皮筋效应”,也就是说,随着点有规律地移动,曲线将产生皮筋伸引一样的变换,带来视觉上的冲击。
线性公式
给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出:
二次方公式
二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t)追踪:
三次方公式
P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1或P2;这两个点只是在那里提供方向资讯。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。
曲线的参数形式为:
- Bezier曲线在processing中的使用
这些曲线由一系列锚点和控制点定义。前两个参数指定第一个锚点,后两个参数指定另一个锚点。中间参数指定了定义曲线形状的控制点。
- 建立婴儿类
class Baby {
public Baby() {
super();
background(254, 242, 242);
}
public void drawBaby() {
this.drawHead();
this.drawCloth() ;
this.drawHands();
this. drawBottle();
this.drawWings();
}
//draw head of the baby
public void drawHead() {
//noFill();
fill(253, 235, 211);
strokeWeight(2);
stroke(0);
bezier(371, 266, 340, 183, 402, 104, 494, 108);
noStroke();
bezier(371, 266, 524, 316, 524, 316, 494, 108); //fillcolor
stroke(0);
bezier(494, 108, 584, 114, 628, 151, 631, 228);
noStroke();
bezier(494, 108, 468, 278, 548, 323, 631, 228);//fillcolor
stroke(0);
bezier(631, 228, 628, 247, 633, 242, 609, 291);
noStroke();
bezier(631, 228, 477, 228, 477, 228, 609, 291);
stroke(0);
bezier(609, 291, 614, 329, 578, 368, 506, 361);
noStroke();
bezier(609, 291, 559, 227, 498, 265, 506, 361);
stroke(0);
bezier(506, 361, 420, 353, 420, 353, 371, 266);
noStroke();
bezier(506, 361, 561, 261, 499, 255, 371, 266);
circle(530, 231, 150);
stroke(0);
//draw eye
fill(34, 48, 93);
circle(477, 291, 25);
circle(586, 292, 25);
fill(248, 248, 235);
circle(477, 291, 10);
circle(586, 292, 10);
//draw ear
arc(382, 292, 30, 40, 0, TWO_PI-QUARTER_PI);
circle(383, 289, 10);
//draw hair
noFill();
bezier(486, 187, 490, 207, 489, 204, 502, 212);
bezier(517, 190, 515, 205, 513, 204, 524, 215);
bezier(547, 187, 557, 200, 554, 204, 541, 214);
}
//draw cloth of the baby
public void drawCloth() {
fill(248, 248, 235);
bezier(432, 346, 406, 394, 401, 393, 393, 450);
arc(404, 463, 60, 30, QUARTER_PI/2, PI+HALF_PI);
arc(469, 466, 80, 40, QUARTER_PI/2, PI);
arc(469, 466, 80, 40, QUARTER_PI/2, PI);
arc(540, 466, 70, 40, QUARTER_PI/2, PI);
//line();
}
//draw hands of the baby
public void drawHands() {
pushMatrix();
translate(460, 378);
rotate(radians(45));
translate(-460, -378);
ellipse(460, 378, 50, 60);
popMatrix();
ellipse(490, 352, 40, 40);
}
//draw feedingBottle belongs to the baby
public void drawBottle() {
FeedingBottle bottle=new FeedingBottle(540, 400, 60, 80, color(228, 243, 250), color(147, 220, 203), color(245, 236, 141), color(249, 246, 203));
bottle.setLineColor(color(0, 0, 0));
bottle.setScale(1.3);
bottle.drawAllBottle();
}
//draw wings of the baby
public void drawWings() {
noFill();
bezier(427, 345, 391, 323, 397, 316, 369, 352);
bezier(369, 352, 356, 374, 365, 375, 385, 368);
bezier(385, 368, 377, 370, 378, 386, 399, 378);
bezier(399, 378, 400, 370, 398, 386, 409, 385);
}
}
- 绘制的婴儿展示
(2)少年时期的设计:书本
我的少年时期,陪伴我最多的就是书本。因此这个时期,我通过绘制书本,来衬托出当时的自己,同时在这个步骤中,加入了鼠标交互相关的内容
- 书本类:书本类的绘制这里不多说,因为就是通过绘制矩形实现的。
class Book {
private float x;
private float y;
private float w;
private float h;
private String s;
private color c=color(255, 255, 0);
public Book() {
super();
}
public Book(float x, float y, float w, float h, color c, String s) {
super();
this.x=x;
this.y=y;
this.w=w;
this.h=h;
this.c=c;
this.s=s;
}
public void setColor(color c)
{
this.c=c;
}
public void setString(String s) {
this.s=s;
}
public void drawBook() {
//
//151, 232, 204
background(75,194,112);
fill(c);
noStroke();
rect(x, y, w, h);
fill(255);
//fill(0);
text(s, x+w/2.5, y+w/2);
//stroke();
}
public void judge(float x, float y) {
if (x>this.x&&x<this.x+this.w&&y>this.y&&y<this.y+this.h) {
this.c=color(random(125, 255), random(225, 255), random(0, 255));
}
}
}
- 交互设计
通过在书本类中设置一个类的成员函数judge得以实现。其中参数传入的是鼠标的坐标值:mouseX,mouseY,当鼠标放置在该书本上时,将会通过随机数,来改变书本的颜色。同时通过滚轮滑动的函数,来改变书本的大小
public void judge(float x, float y) {
if (x>this.x&&x<this.x+this.w&&y>this.y&&y<this.y+this.h) {
this.c=color(random(125, 255), random(225, 255), random(0, 255));
}
}
int ahead=0;//判断滚轮是向前还是向后移动
void mouseWheel(MouseEvent event) {
ahead=event.getCount();
if(ahead>0){
book.setWidth(15);
book.setHeight(20);
}
if(ahead<0){
book.setWidth(-15);
book.setHeight(-20);
}
}
- 效果展示
(3)青年时期的设计:舞蹈的我
青年时期的我,爱好跳舞,享受舞蹈带给我的感觉,喜欢在舞台上的每一刻,也留恋练习时的每一份努力。
- bezierVertex()绘制填充颜色的封闭区域的曲线
<1> 指定贝塞尔曲线的顶点坐标。关于bezier曲线的绘制,我在上面已经介绍过
<2> 每个对bezierVertex()的调用都定义了贝塞尔曲线的两个控制点和一个锚点的位置,向一条线或形状添加一个新段。
<3>第一次在beginShape()调用中使用bezierVertex()时,必须以对vertex()的调用作为前缀来设置第一个锚点。
<4>这个函数必须在beginShape()和endShape()之间使用,并且只有在没有为beginShape()指定模式参数的情况下才可以使用。- 舞蹈的我的类的建立
class Gril {
color c;
public Gril() {
super();
}
public void drawGril() {
//this.drawFlower();
this. drawHair();
this.drawFace();
this.drawBody();
this.drawFoot();
this.drawDress();
}
public void drawHair() {
fill(58, 65, 58);
stroke(58, 65, 58);
beginShape();
vertex(433, 115);
bezierVertex(430, 106, 400, 115, 405, 146);
bezierVertex(405, 181, 392, 195, 360, 237);
bezierVertex( 335, 254, 326, 258, 330, 302);
bezierVertex( 427, 302, 502, 302, 530, 277);
bezierVertex(564, 254, 566, 222, 526, 168);
bezierVertex(505, 152, 508, 162, 487, 125 );
bezierVertex(471, 103, 448, 100, 433, 115 );
endShape();
}
public void drawFace() {
noStroke();
fill(248, 211, 199);
pushMatrix();
translate(443, 159);
rotate(radians(-25));
translate(-443, -159);
ellipse(443, 159, 50, 70);
popMatrix();
}
public void drawShirtPartBig() {
//stroke(0);
bezier(485, 269, 324, 293, 312, 322, 329, 421);
bezier(485, 269, 482, 378, 447, 419, 329, 421);
stroke(this.c);
line(485, 269, 329, 421 );
}
public void drawDress() {
noStroke();
this.c=color(239, 157, 169, 160);
fill(this.c);
pushMatrix();
translate(380, 367);
translate(-400, -347);
this.drawShirtPartBig();
popMatrix();
pushMatrix();
translate(475, 390);
rotate(radians(-20));
translate(-400, -347);
this.drawShirtPartBig();
popMatrix();
this.c=color(255, 204, 213, 160);
fill(this.c);
noStroke();
pushMatrix();
translate(543, 418);
rotate(radians(-60));
translate(-400, -347);
this.drawShirtPartBig();
popMatrix();
translate(-5, 0);
//draw the dress after body
fill(252, 132, 154, 160);
stroke(252, 132, 154, 160);
beginShape();
vertex(468, 310);
bezierVertex(386, 277, 360, 287, 331, 323);
bezierVertex(316, 378, 315, 377, 337, 423);
bezierVertex(361, 413, 346, 411, 438, 419);
bezierVertex(458, 371, 464, 339, 468, 310);
endShape();
fill(247, 160, 176, 220);
stroke(247, 160, 176);
beginShape();
vertex(513, 283);
bezierVertex(494, 291, 491, 297, 469, 300);
bezierVertex(429, 402, 432, 423, 469, 474);
bezierVertex(482, 482, 486, 489, 489, 502);
bezierVertex(500, 503, 512, 505, 518, 505);
bezierVertex(553, 488, 556, 486, 572, 455);
bezierVertex(583, 393, 576, 369, 513, 283);
endShape();
stroke(254, 95, 123);
fill(254, 95, 123, 250);
//draw the dress before
beginShape();
vertex(499, 168);
bezierVertex(531, 206, 529, 190, 530, 275);
bezierVertex(533, 305, 560, 331, 613, 357);
bezierVertex(636, 377, 638, 380, 633, 438);
bezierVertex(628, 453, 628, 453, 593, 473);
bezierVertex(594, 465, 594, 469, 594, 480);
bezierVertex(568, 462, 578, 476, 567, 433);
bezierVertex(552, 380, 562, 398, 530, 354);
bezierVertex(521, 339, 517, 328, 513, 281);
bezierVertex(460, 317, 440, 322, 384, 314);
bezierVertex(357, 308, 355, 306, 318, 325);
bezierVertex(297, 332, 297, 331, 287, 324);
bezierVertex(312, 310, 312, 316, 324, 286);
bezierVertex(382, 250, 371, 245, 446, 268);
bezierVertex(476, 278, 451, 276, 485, 269);
bezierVertex(478, 242, 485, 254, 460, 228);
bezierVertex(453, 219, 445, 206, 442, 200);
bezierVertex(443, 198, 448, 196, 454, 196);
bezierVertex(473, 208, 475, 208, 505, 212);
bezierVertex(505, 191, 507, 201, 494, 173);
bezierVertex(494, 172, 497, 169, 499, 168);
endShape();
}
public void drawBody() {
stroke(248, 207, 199);
fill(248, 207, 199);
//noFill();
translate(0, 18);
beginShape();
vertex(468, 165);
bezierVertex(478, 175, 483, 176, 497, 166);
bezierVertex(509, 154, 535, 135, 549, 120);
bezierVertex(554, 121, 586, 56, 603, 50);
bezierVertex(587, 67, 591, 67, 599, 64);
bezierVertex(587, 71, 579, 83, 563, 128);
bezierVertex(538, 154, 530, 168, 489, 206);
endShape();
beginShape();
vertex(454, 175);
bezierVertex(468, 184, 466, 190, 448, 198);
bezierVertex(431, 204, 408, 205, 398, 205);
bezierVertex(380, 211, 358, 216, 320, 223);
bezierVertex(307, 220, 298, 222, 283, 227);
bezierVertex(291, 229, 313, 228, 296, 235);
bezierVertex(312, 237, 312, 236, 318, 232);
bezierVertex(376, 217, 388, 217, 509, 226);
endShape();
beginShape();
vertex(468, 165);
bezierVertex(478, 175, 483, 176, 497, 166);
bezierVertex(498, 187, 502, 199, 502, 213);
bezierVertex(490, 209, 468, 205, 448, 198);
bezierVertex( 448, 198, 466, 190, 454, 175);
endShape();
}
public void drawFoot() {
beginShape();
vertex(468, 478);
bezierVertex(469, 508, 467, 502, 475, 542);
bezierVertex(470, 544, 466, 548, 462, 553);
bezierVertex(468, 563, 468, 557, 464, 578);
bezierVertex(465, 585, 460, 577, 477, 590);
bezierVertex(490, 591, 488, 591, 478, 579);
bezierVertex(482, 555, 485, 531, 489, 502);
bezierVertex(486, 475, 482, 466, 468, 478);
endShape();
beginShape();
vertex(321, 390);
bezierVertex(312, 396, 308, 398, 304, 402);
bezierVertex(298, 404, 299, 403, 292, 397);
bezierVertex(283, 402, 279, 405, 259, 419);
bezierVertex(254, 433, 253, 432, 270, 423);
bezierVertex(292, 409, 285, 414, 328, 405);
bezierVertex(335, 392, 338, 392, 321, 390);
endShape();
}
- 增加交互(通过鼠标点击,改变裙子的颜色)
///鼠标点击可以改变裙子的颜色
void mouseClicked() {
gril.addColor(random(-255,255),random(-255,255),random(-255,255));
}
- 绘制效果展示
- 动态效果展示
三、设计效果展示
- 融合三个时期:用不同的古诗文代表每个时期
- 通过设置帧,来控制显示绘制内容
系统变量frameCount包含自程序启动以来显示的帧数。在setup()中,值是0,在draw的第一次迭代之后,值是1,依此类推。
if (frameCount%1650<100)
{
//第一幕
fill(255);
textSize(80);
text("我", width/2-20, height/2);
} else if (frameCount%1650<200) {
//第二幕
textSize(30);
text("一半在风里张扬,一半在尘土里安详", 300, height/2);
} else if (frameCount%1650<300 ) {
textSize(30);
text("一半洒落阴凉,一半沐浴阳光", 325, height/2);
} else if (frameCount%1650<400) {
textSize(60);
text("童年篇", width/2-75, height/2-100);
textSize(30);
text("儿童放学归来早,忙趁东风放纸鸢", 300, height/2);
} else if (frameCount%1650<500) {
background(254, 242, 242);
bottle1.drawAllBottle();
} else if (frameCount%1650<600) {
background(254, 242, 242);
baby. drawBaby();
} else if (frameCount%1650<700) {
textSize(60);
fill(255);
text("少年篇", width/2-75, height/2-100);
textSize(30);
text("纸上得来终觉浅,得知此事要躬行", 300, height/2);
} else if (frameCount%1650<800) {
background(255);
book.setColor(color(218 ,233, 37));
book.setString("语文");
book.judge(mouseX, mouseY);
book.drawBook();
} else if (frameCount%1650<900) {
background(255);
book.setString("数学");
book.setColor(color(255 ,128, 128));
book.judge(mouseX, mouseY);
book.drawBook();
} else if (frameCount%1650<1000) {
background(255);
book.setString("英语");
book.setColor(color(21 ,159, 238));
book.judge(mouseX, mouseY);
book.drawBook();
} else if (frameCount%1650<1100) {
background(255);
book.setString("化学");
book.setColor(color(20 ,121, 211));
book.judge(mouseX, mouseY);
book.drawBook();
} else if (frameCount%1650<1200) {
background(255);
book.setString("物理");
book.setColor(color(126,126,0));
book.judge(mouseX, mouseY);
book.drawBook();
} else if (frameCount%1650<1300) {
textSize(60);
fill(255);
text("青年篇", width/2-50, height/2-100);
textSize(30);
text("高堂满地红氍毹,试舞一曲天下无", 300, height/2);
}else if (frameCount%1650<1450) {
background(255);
gril.drawGril();
} else if (frameCount%1650<1650) {
textSize(40);
text("人生未完,待续……", width/2-150, height/2);
}
- 整体效果展示