一、制作背景
最近沉迷于迪士尼的系列动画《怪诞小镇》,这是一部一看就上瘾,看完就空虚的不同寻常的佳作。旋律简单但是引人入胜的背景音乐,艳丽色彩可爱画风下的诡异童话,看似平凡渺小却让人难以忘怀的角色,还会到来的暑假和再也不会有的续集,让人赞叹之余又不免有些惋惜。
或许有一天,你也会迷失森林,夜晚踏入Uncle Stan的神秘小屋,遇到Mabel和Dipper,一起发现这个小镇里不为人知的秘密······
二、功能操作
程序有四个模块,是四个不同的场景。
场景一是动态的Gravity Falls标题,以及可以交互控制播放/暂停的音乐——动画op《Made Me Realize》。按键“M”控制音乐。
场景二是Bill也想变可爱,在这个场景Bill姥爷会跟随鼠标,点击左键会落下五颜六色的三角,拖曳鼠标也会有对应效果。
场景三是随机游走产生的图案。
场景四是Bill姥爷标志性的三角符号。
场景切换对应按键:
A—场景一;
S—场景二;
D—场景三;
F—场景四
演示视频:
三、模块代码
场景一的音乐插件:
import
ddf.minim.*;
Minim minim;
AudioPlayer player;
场景一动态字体的绘制:
PFont font = createFont("Phetsarath_OT.ttf",32);
textFont(font, 200);
text("Gravity", 80, 180);
text("Falls", 190, 340);
float step = 10;
for (float x = 0; x < width; x+= step) {
for (float y = 0; y < height; y += step) {
if (brightness(get((int)x, (int)y)) > 100) {
sprites.add(new Sprite(new PVector(x, y)));
}
}
}
······
场景二Bill的绘制:
fill(255,255,0);
strokeWeight(2);
triangle(mouseX,-1.732*50+mouseY,-50+mouseX,mouseY,50+mouseX,mouseY);
fill(0);
rect(mouseX-5,-1.732*50+mouseY-40,10,40);
rect(mouseX-4,mouseY-50*0.27*1.732-2,8,4);
triangle(mouseX,mouseY-50*0.27*1.732,mouseX-50*0.3,mouseY-50*0.27*1.732-6,
mouseX-50*0.3,mouseY-50*0.27*1.732+6);
triangle(mouseX,mouseY-50*0.27*1.732,mouseX+50*0.3,mouseY-50*0.27*1.732-6,
mouseX+50*0.3,mouseY-50*0.27*1.732+6);
noFill();
strokeWeight(2);
//translate(mouseX,(-1.732*50+mouseY)/3);
arc(mouseX,mouseY-48,32,32,PI*7/6,PI*11/6);
arc(mouseX,mouseY-64,32,32,PI/6,PI*5/6);
arc(mouseX,mouseY-55.5,6,10,PI/2,PI*3/2);
arc(mouseX,mouseY-55.5,6,10,PI*3/2,PI*5/2);
strokeWeight(1);
line(mouseX,mouseY-66,mouseX,mouseY-69);
line(mouseX-6,mouseY-63,mouseX-7,mouseY-69);
line(mouseX+6,mouseY-63,mouseX+7,mouseY-69);
line(mouseX,mouseY-48,mouseX,mouseY-45);
line(mouseX-8,mouseY-50,mouseX-12,mouseY-45);
line(mouseX+8,mouseY-50,mouseX+12,mouseY-45);
line(mouseX-18,-1.732*50+mouseY,mouseX+18,-1.732*50+mouseY);
//1
line(mouseX-50*0.6,mouseY-50*0.4*1.732,mouseX+50*0.6,mouseY-50*0.4*1.732);
//2
line(mouseX-50*0.73,mouseY-50*0.27*1.732,mouseX+50*0.73,mouseY-50*0.27*1.732);
//3
line(mouseX-50*0.88,mouseY-50*0.12*1.732,mouseX+50*0.88,mouseY-50*0.12*1.732);
line(mouseX-50*0.4,mouseY-50*0.4*1.732,mouseX-50*0.4,mouseY-50*0.27*1.732);
line(mouseX+50*0.4,mouseY-50*0.4*1.732,mouseX+50*0.4,mouseY-50*0.27*1.732);
line(mouseX-50*0.5,mouseY-50*0.27*1.732,mouseX-50*0.5,mouseY-50*0.12*1.732);
line(mouseX+50*0.5,mouseY-50*0.27*1.732,mouseX+50*0.5,mouseY-50*0.12*1.732);
line(mouseX,mouseY-50*0.27*1.732,mouseX,mouseY-50*0.12*1.732);
line(mouseX-50*0.3,mouseY-50*0.12*1.732,mouseX-50*0.3,mouseY);
line(mouseX+50*0.3,mouseY-50*0.12*1.732,mouseX+50*0.3,mouseY);
strokeWeight(3);
//zuo shou
arc(mouseX-46,mouseY-33,32,18,PI/6,PI*5/6);
arc(mouseX-65,mouseY-33,16,12,PI/6,PI*5/6);
arc(mouseX-64,mouseY-34,12,14,PI*11/6,PI*13/6);
arc(mouseX-69,mouseY-33,24,26,PI/6,PI/2);
arc(mouseX-63,mouseY-25,8,20,0,PI/2);
//you shou
arc(mouseX+46,mouseY-33,32,18,PI/6,PI*5/6);
arc(mouseX+65,mouseY-33,16,12,PI/6,PI*5/6);
arc(mouseX+64,mouseY-34,12,14,PI*5/6,PI*7/6);
arc(mouseX+69,mouseY-33,24,26,PI/2,PI*5/6);
arc(mouseX+63,mouseY-25,8,20,PI/2,PI);
line(mouseX-50*0.4,mouseY,mouseX-50*0.4,mouseY+25);
arc(mouseX-10,mouseY+25,20,30,PI/2,PI);
line(mouseX-10,mouseY+42,mouseX-12,mouseY+53);
line(mouseX+50*0.4,mouseY,mouseX+50*0.4,mouseY+25);
arc(mouseX+10,mouseY+25,20,30,PI*2,PI*5/2);
line(mouseX+10,mouseY+42,mouseX+12,mouseY+53);
场景三随机游走:
class Phasor {
float inc;
float phase;
Phasor(float inc) {
this.inc = inc;
}
void update() {
phase += inc;
while (phase >= 1.0) {
phase -= 1.0;
}
while (phase < 0) {
phase += 1.0;
}
}
}
class Walker {
PVector v;
Walker(float x, float y) {
v = new PVector(x, y);
}
void update() {
float gauss = p2.phase * random(2);
v = getVCoordinates(v, gauss, angles[int(random(angles.length))]);
float offset = width / 4;
if (v.x >= width + offset) {
v.x -= width + offset;
}
if (v.x < -offset) {
v.x += width + offset;
}
if (v.y >= height + offset) {
v.y -= height + offset;
}
if (v.y < 0) {
v.y += height + offset;
}
float a = getAngleFromCenter(v);
float d = dist(v.x, v.y, width / 2, height / 2);
PVector center = new PVector(width / 2, height / 2);
float rAngle = PI / (float) nReflections;
noStroke();
fill(palette.getNorm(p.phase), map(d, 0, width, 64, 12));
gauss = max(0.5, gauss / 2);
for (int i = 0; i < nReflections; i++) {
float thisAngle = a + (TWO_PI / (float) nReflections) * i;
PVector thisV = getVCoordinates(center, d, thisAngle);
ellipse(thisV.x, thisV.y, gauss, gauss);
thisV = getVCoordinates(center, d, PI - thisAngle);
ellipse(thisV.x, thisV.y, gauss, gauss);
}
}
}
······
场景四的噪点:
void noise() {
noStroke();
strokeWeight(1);
for (int i = 0; i < width - 1; i += 5) {
for (int j = 0; j < height - 1; j += 5) {
fill(random(0, 255), random(30, 50));
rect(random(i - 5, i), random(j - 5, j), 1, 1);
}
}
for (int i = 0; i < 5; i++) {
fill(random(0, 255), 255);
rect(random(0, width), random(0, height), 2, 2);
}
}
四、参考资料
1、《代码本色》
2、https://www.openprocessing.org/
五、作业评价
推荐作业一:https://blog.csdn.net/wangyouxu24/article/details/89554177
评价:小球的交互很有创意,很美观,而且和游戏机制结合,游戏过程中还有说明、按钮、文字提示,很完整很成熟,非常有趣。
推荐作业二:https://zhuanlan.zhihu.com/p/64726213
评价:创意非常新颖,界面的简笔画画风很可爱,是一个简单的生态模拟游戏,看到食草动物吃草,食肉动物吃食草动物,非常有趣,可是食草动物的死亡概率太高了OVO,应该给它们一个从食肉动物嘴里逃脱的概率。
推荐作业三:https://zhuanlan.zhihu.com/p/64726213
评价:审美太好了,创意又新颖又可爱又贴近实际,画面很温馨很治愈,很有设计感。拔头发模拟的效果特别好,眼球跟随的细节也好评,我可以玩一年!!!!!