互动媒体技术——创意编程

作品一:代码生成爱心

总体步骤概述

1.观察图形,总结其中的规律
2.将规律一步一步转化为代码,注意封装性
3.应用交互性和用户感官,拓展作品

一、观察图形、总结规律

在这里插入图片描述

(1)单个爱心:

单个爱心是由许多个立方体拼接而成的,每行方块的位置不同以及个数不同,但是每个小方块的大小相同。方块的边框是没有消隐的。

(2)整体爱心的位置:

4*4个爱心,每行4个,每列4个,间隔相等。
在这里插入图片描述

(3)整体爱心的运动:

在这里插入图片描述
<1>.可以观察到,每一斜排的爱心的运动是一致的,因此每一斜排可以归为1组。第一排和最后一排是一致的,因此这两排为一组。一共有六组。
<2>.从第一排到最后一排,正好转过360°,因此六组,每组间隔360°÷6=60°。设置起点不同即可,但是运动速率是一致的。

二、将规律一步一步转化为代码,注意封装性

(1)编写单个爱心

<1>首先想到,16个爱心,不可能每一个都写一段代码来绘制爱心,所以我们可以建立一个爱心的类,给它添加一个绘制爱心的功能

class lovePitch{
	public void drawLove2(){
	}
}

<2>而既然要绘制爱心的话,当然得指定绘制爱心所在的位置,所以该类需要拥有成员变量:爱心的位置、爱心的颜色、组成爱心的方块大小,这里可以在构造函数中进行设置

class lovePitch{
  lovePitch(){
	    
	  }
  lovePitch(float x,float y,float z,float size,int startAngle){
    this.x=x;
    this.y=y;
    this.z=z;
    this.size=size;
    this.startAngle=startAngle;
    this.c=color(255,0,0);
  }
}

<3>开始绘制爱心的函数编写:
绘制爱心时,得先学会写3D效果的方格,因此我们先构建一下3D的方块。查到官方API给出了参考:
在这里插入图片描述
使用两个for循环开始编写爱心桃,一共是6行,7列,其中有一些缺省,使用if语句就可以判断是画还是不画。这里使用了popMatrix()和pushMatrix()可以保存和还原之前的状态。
在这里插入图片描述

 public void drawLove2(){
    pushMatrix();
    translate(x,y,z);
    fill(c);
    ortho(); 
    for(int j=0;j<6;j++){
      for(int i=0;i<7;i++){
        pushMatrix();
        translate(size*i,size*j,0); 
        if((j==0&&(i==0||i==3||i==6))||(j==3&&(i==0||i==6))||(j==4&&(i!=2&&i!=3&&i!=4))||(j==5&&(i!=3))){
        }
        else box(size);
        popMatrix();
      }
    }
    popMatrix();
  }
(2)考虑爱心的旋转

每个爱心的旋转速度是一致的,只是初始的旋转位置不同。考虑到这个,可以把爱心的旋转写到爱心类中,并传递一个起始位置的参数即可。又因为,旋转是由一个变量的角度所控制的,因此也要将控制爱心旋转的角度的变量作为参数传递进去。(由于processing中的旋转绕的中心都是坐标原点,因此这采用先将物体以到原点,将物体旋转后,再移回原来位置的办法

 public void rotateLove(int rotateMills){    
    pushMatrix();
    translate(x+30,0,0);
    rotateY(radians(rotateMills));
    rotateY(radians(startAngle));
    translate(-(x+30),0,0);
    drawLove2();
    popMatrix();   
  }
(3)绘制所有爱心

4行4列的话,我们可以采用三个变量控制:
i:控制16个爱心的绘制
j:控制换行,每4绘制4个。换一行,可以采用求余的办法确定,每一行的位置通过(j行距离值)确定。
k:控制每一列,每个爱心桃的列的位置通过(i
列间距)确定。
(1)首先再所有函数的开头需要声明类对象,并指定参照爱心桃的初始坐标:

lovePitch[] allLove=new lovePitch[16];
int firstX=50;
int firstY=50;

(2)然后在setup()函数中初始化类,其中rateLove为每个爱心桃的初始旋转角度,因为每排爱心的初始角度是不一致的

void setup(){
  size(500,500,P3D);
  int[] rateLove={0,60,120,180,60,120,180,240,120,180,240,300,180,240,300,0};
  for(int i=0,j=0,k=0;i<16;i++,k++){
    allLove[i]=new lovePitch(firstX+(k*100),firstY+(j*100),0,10,rateLove[i]);
    if((i+1)%4==0){
      j++;
      k=0;
      k--;
    }  
  }
}

(3)最后可以在draw函数中使用for循环,调用绘制函数即可。(其中i1为旋转角度的控制变量,为全局变量,当i达到360时,即旋转一周,此时重置i1,避免数值过大,超过了int的范围)

void draw(){
    background(0);
    for(int i=0;i<16;i++)
    {
      allLove[i].rollover(mouseX,mouseY);
      allLove[i].rotateLove(i1);
    }
   
    i1++;
    if(i1==360)i1=0;
}

(4)效果展示
在这里插入图片描述

三、3.应用交互性和用户感官,拓展作品

processing中最有特色的便是交互性了,因此这里我通过与用户进行交互的原则,对作品进行了扩展。通过鼠标来实现对爱心桃颜色的控制,实现的功能有:
(1)鼠标按下时,改变爱心的颜色,鼠标再次按下,恢复颜色
在这里插入图片描述
<1>首先编写鼠标相应事件
flag为全局变量,用于判断当前鼠标是否点下

void mouseClicked() {
  if(flag)flag=false;
  else flag=true;
}

<2>编写改变颜色的函数:(该函数针对每一个爱心桃而改变颜色,因而为爱心这个类的成员函数)

 public void changeColor(){
    if(flag)this.c=color(random(0,255),random(0,255),random(0,255));
    else this.c=color(255,0,0);
  }

(2)鼠标移动到某一个爱心上面时,改变所指到之处爱心的颜色和速度。
在这里插入图片描述
颜色改是相对于每一个爱心而言的,因此应该为爱心类添加一个成员函数(其中if是判断鼠标当前的位置是否处在该爱心的矩形边框中)

 public void rollover(int mx,int my){
    if(mx>x&&mx<x+6*size&&my>y-10&&my<y+4*size){
       this.c=color(random(0,255),random(0,255),random(0,255));
       this.speed=200;
    }else{
      this.c=color(255,0,0);
      this.speed=0;
    }

作品二:花瓣绘制

总体步骤概述

1.观察图形,总结其中的规律
2.将规律转化为代码,注意封装性
3.应用鼠标的交互性,拓展作品

一、观察图形,总结其中的规律

在这里插入图片描述

(1)形状特点:
  • 一共有7层花,7圈
  • 每一圈有12个椭圆形的花瓣
  • 随着半径的减小,椭圆的大小也在发生变化,越来越小
(2) 角度特点
  • 12个椭圆平分360°,因此每个椭圆占360°/12=30°
    在这里插入图片描述
  • 一共7层,每单数层首个椭圆的起始角度是0,每双数层首个椭圆的起始角度是15°
    在这里插入图片描述
(3)颜色特点

随着半径的减小,颜色RGB中的G的值逐渐增大,R的值几乎维持在252左右,G的值越大,越黄。

(4)动态特点

可以观察到,随着时间的变换,花瓣的颜色在变浅,逐渐显现出边框。因此可以判断,颜色值中的alpha值在改变。且改变的差值与半径大小成正比

二、将规律转化为代码,注意封装性

(1)第一步:绘制出最外圈的一层花瓣
  • 每一圈的椭圆构成的花瓣是以圆形排布的,因此这里确定每一个椭圆的位置时,应该使用圆的坐标计算。圆的坐标这里建议选取极坐标,因为涉及到每个椭圆还需旋转一定角度的问题。
    圆的极坐标表示为:
    在这里插入图片描述
    在这里插入图片描述
  • 这里我们先建立一个绘制每一个花瓣的类(即一个椭圆)
    x:椭圆绘制的中心的x坐标
    y:椭圆绘制的中心的y坐标
    w:椭圆的宽度
    h:椭圆的高度
    c:椭圆的颜色
class Circle{
  float x;
  float y;
  float w;
  float h;
  color c;
  public Circle(){
  }
  public Circle(float x,float y,float w,float h,color c ){
     this.x=x;
     this.y=y;
     this.w=w;
     this.h=h;
     this.c=c;
  }
  • 为该类添加一个旋转的成员函数(因为每一个椭圆的角度是不一致的,因此这里需要改变角度)
public void   rotateSelf(float angle1){
    pushMatrix();
    translate(x,y);
    rotate(angle1);
    translate(-x,-y);
    drawCircle();
    popMatrix();
  }
 public void drawCircle(){
    fill(c);
    ellipse(x,y,w,h);
  }
  • 每一层由12个花瓣组成,因此建立一圈的话,可以看为一组,这里可以建立一个类对象数组
Circle[] circle=new Circle[12];
  • 进行对象的的初始化以及绘制
    (1)之前已经知道,每30°绘制一个椭圆,那么椭圆到底绘制多大会较好呢?有可能会绘制的太大有重合,有可能绘制得太小,又间隔太大。
    在这里插入图片描述
    在这里插入图片描述
    这里就需要使用数学计算了,通过使用弧长公式:
    K=nPIR/180
    因为每个椭圆对应的角度是30°,因此每一个椭圆的宽度最大应该是:30PIR180=PIR/2
 for(int i=0;i<12;i++)
    {
      circle[j][i]=new Circle(100,100,120-10*j,PI*R/6.0,allcolor[j]);
      if(choose==(i+3)||choose==(i+4)||choose==i||(i+1)==choose||(i+2)==choose){
        circle[j][i].setColor(color(allcolor[j],200+5*(j+1)));
      }
      circle[j][i].setLocation(R*cos(radians(angle)),R*sin(radians(angle)));
      circle[j][i].rotateSelf(radians(angle));
      angle+=30;
    }
  • 因此就绘制出了这样的一圈花瓣
    在这里插入图片描述
(2)绘制出7层的花瓣

因为一个for循环可以绘制出一圈圆,所以7个for循环就能画出所有层。这里我们可以通过二维数组来绘制。

  • 首先需要将之前的circle数组换为二维数组,并制定好每一层的颜色
Circle[][] circle=new Circle[7][12];
color[] allcolor={color(252,109,0),color(253,130,0),color(252,148,0),color(253,171,0),color(253,192,0),color(252,211,0),color(253,232,0)};
  • 指定单层、双层的角度,因为单双层绘制起始的椭圆的位置不一致
int angle1=0;
int angle2=15;
int angle;
  • 开始绘制
 for(int j=0;j<7;j++){
     if(j%2==0)angle=angle2;
      else angle=angle1;
   for(int i=0;i<12;i++)
    {
      circle[j][i]=new Circle(100,100,120-10*j,PI*R/6.0,allcolor[j]);
      if(choose==(i+3)||choose==(i+4)||choose==i||(i+1)==choose||(i+2)==choose){
        circle[j][i].setColor(color(allcolor[j]));
      }
      circle[j][i].setLocation(R*cos(radians(angle)),R*sin(radians(angle)));
      circle[j][i].rotateSelf(radians(angle));
      angle+=30;
    }
   // R-=5*(7-j);
    if(j==6)R=200;
  }
(3)增加动态效果(忽明忽暗)
  • 这里只需要更改椭圆的颜色中的alpha通道的值即可,可以观察到,每一层的alpha的改变程度是不一致的,外层的越暗,内层的越亮,这里我们可以把它看成一个线性的变化color(allcolor[j],200+5*(j+1)),以层数作为线性变换中的变量即可。
 for(int j=0;j<7;j++){
     if(j%2==0)angle=angle2;
      else angle=angle1;
   for(int i=0;i<12;i++)
    {
      circle[j][i]=new Circle(100,100,120-10*j,PI*R/6.0,allcolor[j]);
      if(choose==(i+3)||choose==(i+4)||choose==i||(i+1)==choose||(i+2)==choose){
        circle[j][i].setColor(color(allcolor[j],200+5*(j+1)));
      }
      circle[j][i].setLocation(R*cos(radians(angle)),R*sin(radians(angle)));
      circle[j][i].rotateSelf(radians(angle));
      angle+=30;
    }
    R-=5*(7-j);
    if(j==6)R=200;
  }
  • 效果展示
    在这里插入图片描述

三、应用鼠标的交互性,拓展作品

鼠标可以拖动椭圆,能够一层一层的生成和使花瓣消失
消失:设置花瓣的颜色为黑色即可
判断位置:为花瓣类设置一个坐标的判断函数即可

 public void judgeEnter(float mousex,float mousey){
    color record=this.c;
    if(mousex>x-w+400&&mousex<x+w+400&&mousey>y-h+400&&mousey<y+h+400){
      record=this.c;
      this.c=color(0);
    }else{
      this.c=record;
    }
  }

在这里插入图片描述

作品三:方块旋转

总体步骤概述

1.观察图形,总结其中的规律
2.将规律转化为代码,注意封装性
3.应用交互性,拓展作品

一、观察图形,总结其中的规律

在这里插入图片描述

(1)图形组成元素

图形是由三个立方体的线框图以及立方体的每个顶点防止一个小球所形成。

(2)图形运动特征

可以观察,三个立方体均在旋转,但是每个立方体的旋转轴却不一样。这里看似简单,但是涉及到很多步的角度的转换。
首先了解一下processing的坐标系:
在这里插入图片描述
最外圈的立方体:这里先看作绕Y轴旋转
中间的立方体:绕x轴旋转
最小的立方体:绕Z轴旋转
当然,它们还需要旋转一定的角度

二.将规律转化为代码,注意封装性

第一步:分析类的关系

(1)首先每个cube都有绘制、size等成员,因此得建立一个cube类,其中包含绘制cube和设置cube大小的功能
(2)由于每个cube的旋转角度不一致,所以每个cube的旋转的方法都不一样,但可以只是内容不一样,但是方法名相同,这里我们想到的第一个便是接口。
于是分析了一下,整体的结构大致是:
在这里插入图片描述

第二步:开始编写每一块的代码
  • Cube类:在这个类中,我把小球的绘制也放在了绘制函数一起,这样子方便看作是一个整体。
class Cube {
  float size;
  color c;
  Cube() {
  }
  Cube(float size) {
    this.size =size;
    
  }
 public void setColor(color c){
   this.c=c;
 }
  public void drawCube() {
    float []x={-size/2,-size/2,-size/2,-size/2,size/2,size/2,size/2,size/2};
    float []y={-size/2,size/2,-size/2,size/2,-size/2,size/2,-size/2,size/2};
    float []z={size/2,size/2,-size/2,-size/2,size/2,size/2,-size/2,-size/2};
    ortho();
    for(int i=0;i<8;i++){
      pushMatrix();
      translate(200, 200, 0);
      rotateX(radians(-45));
      rotateY(radians(45));
      translate(-200, -200, 0);
      translate(x[i]+200,y[i]+200,z[i]);
      //noStroke();
      fill(c);
      lights();
      sphere(5);
      popMatrix();
    }
   
    pushMatrix();
    translate(200, 200, 0);
    ortho();
    strokeWeight(3); 
    stroke(c, 160);
    rotateX(radians(-45));
    rotateY(radians(45));
    lights();
    noFill();
    box(size);
    popMatrix();
  }
}
  • 接口 threeCube
interface threeCube {
  public void rotateTheCube(int rotateMills,int x);
  public void setColor(color c);
}
  • 类Cube1,Cube2,Cube3:它们继承自Cube,实现了结构threeCube,其中只是方法rotateCube(旋转立方体)的函数内容有所不同,因此这里我只介绍一下旋转:
    (1)最外圈的立方体:先移回原点,把x轴和Y轴的角度都恢复到原位,然后绕Y轴旋转,转过后,又将其移回之前的位置和角度(x轴旋转-45度,y轴旋转45°)
public void rotateTheCube(int rotateMills,int x) {
    if(x>0){
      this.size=x;
    }
    pushMatrix();
    translate(200, 200, 0);
    rotateX(radians(-45));
    rotateY(radians(rotateMills));
    rotateX(radians(45));
    translate(-200, -200, 0);
    drawCube();
    popMatrix();
  }
   

(2)中间的立方体:类似上面

public void rotateTheCube(int rotateMills,int x) {
    if(x>0){
      this.size=x;
    }
    pushMatrix();
    translate(200, 200, 0);
    rotateX(radians(-45));
    rotateY(radians(45));
    rotateX(radians(-i));
    rotateY(radians(-45)); 
    rotateX(radians(45));
    translate(-200, -200, 0);
    drawCube();
    popMatrix();
  }

(3)最小的立方体

 public void rotateTheCube(int rotateMills,int x) {
    if(x>0){
      this.size=x;
    }
    pushMatrix();
    translate(200, 200, 0);
    rotateX(radians(-45));
    rotateY(radians(45));
    rotateZ(radians(i));
    rotateY(radians(-45)); 
    rotateX(radians(45));
    translate(-200, -200, 0);
    drawCube();
    popMatrix();
  }

效果展示:
在这里插入图片描述

三、.应用交互性,拓展作品

(1)使用mouseClick函数控制方块的大小变换,flag用于确定是否点下

void mouseClicked() {
  if(flag)flag=false;
  else flag=true;
}
void draw() {
  background(0);
  noFill();
  int caseCube=frameCount%21;
  cube1.setColor(colorCube);
  cube2.setColor(colorCube);
  cube3.setColor(colorCube);
  if(caseCube<7&&flag){
    cube1.rotateTheCube(i+10,120);
    cube2.rotateTheCube(i+5,60);
    cube3.rotateTheCube(i,30);
 
  }
  else if(caseCube<14&&flag){ 
    cube1.rotateTheCube(i+10,60);
    cube2.rotateTheCube(i+5,30);
    cube3.rotateTheCube(i,10);
  }else{
    cube1.rotateTheCube(i+10,180);
    cube2.rotateTheCube(i+5,120);
    cube3.rotateTheCube(i,60);
  }
  i++;
  if(i==360)i=0;
}

(2)使用mouseDragged函数控制方块的颜色变换

color colorCube=color(255, 177,17);
 cube1.setColor(colorCube);
 cube2.setColor(colorCube);
 cube3.setColor(colorCube);
void mouseDragged() 
{
  colorCube=color(random(215,255),random(50,255),random(0,255));
}

效果展示
在这里插入图片描述

发布了28 篇原创文章 · 获赞 4 · 访问量 5404

猜你喜欢

转载自blog.csdn.net/Program_dancing/article/details/102670073