精华内容
下载资源
问答
  • 鲤——processing动画交互应用

    千次阅读 2019-05-03 21:41:50
    鲤——processing动画交互应用 前言 目录 1.应用设计 2.编写过程 3.最终成果 4.参考资料 应用设计 编写过程 最终成果 参考资料

    鲤——processing动画交互应用

    前言

    鲤鱼在我们的日常生活中是一种非常常见的鱼类,它们中的一部分会成为餐桌上的食物,另一部分——锦鲤,则具有极高的观赏价值。我们在园林、寺庙等景点的水池中经常能看见色彩艳丽的各类锦鲤,其中红色和金色的锦鲤最受欢迎。
    我从很久以前就很喜欢锦鲤的形象,不过比起现实中的锦鲤,我更喜欢的是中国风的水墨画或水彩中的锦鲤,无论是细细描绘还是草草勾勒,鱼身的弧度和色泽都显得灵动缥缈,仿佛下一刻这尾鱼儿就会从画中跳出来,一摆尾便消失在视野中。

    说到鲤,说不定有人会想起一款叫《鲤》的游戏,我当初是在taptap上下载到这个游戏的,画面风格和游戏方式都很清新休闲,不过现在好像无法下载了(不知道发生了啥)。这次作业主题也是因为回想起了这部游戏才产生的,想要实现一个可以控制鲤来完成一些任务的小游戏。

    目录

    1.应用设计
    2.编写过程
    3.总结
    4.参考资料
    5.应用推荐

    应用设计

    自己最初的想法虽然好,但在编写过程中遇到的问题太多了,方案也就变得越来越简单,这里就只写最后成型的程序内容吧。
    1.首先是最基本的,鼠标移动控制鲤鱼在池塘中自由游动,并伴有一定的动画效果。
    2.鼠标按下时,会给鱼一个当前方向的力,让鱼儿加速。
    3.鲤鱼游动时会不断吐出泡泡,泡泡受到浮力与重力影响(浮力肯定是要大一点的)向上移动。
    4.随机地在池塘中产生鱼食,产生时会有波纹,鱼食经过一段时间后消失,鲤鱼吃到鱼食时会在当前位置动态出现莲花。
    5.鲤鱼最初为白色,每吃一次鱼食就会加深颜色直到最终变红。
    6.画面上方有文字提醒,当鲤鱼变成最终心态后赋予一个固定的力让鱼游动,游戏结束。
    编写过程将按照设计内容来一一解说。

    编写过程

    1.虽然我也很想自己设计一个完整的鲤鱼动画…不过时间紧迫加上能力限制,最终使用的鲤鱼蓝本来源于一个开源项目(看到这个项目也促使了我做这个主题),我借鉴了其中绘制鲤鱼的一部分代码,是哪个网站找到的我记不得了…
    项目运行页面:http://mylifeaquatic.herokuapp.com/
    github源码:https://github.com/dasl-/my-life-aquatic
    项目源码好像是需要用ruby运行的(不太了解),所以我只看了proccessing文件夹里面的代码进行参考(在public/processing里面),最终借鉴的是三个文件中的部分代码:Boid,Fish和Flagellum。
    Boid类(包括我自己的注释):

    class Boid {
    	public PVector location;
    	public PVector velocity;
    	private PVector acceleration;
    	private float maxForce;
    	private float maxSpeed;
    	
    	public Boid( PVector _location, float _maxSpeed, float _maxForce) {
         createBoid(_location, _maxSpeed, _maxForce);
         velocity= new PVector( random( -maxSpeed, maxSpeed ), random( -maxSpeed, maxSpeed ) );
        }
      private void createBoid(PVector _location, float _maxSpeed, float _maxForce) {
    		location 		= _location;
    		maxSpeed 		= _maxSpeed;
    		maxForce 		= _maxForce;
    		acceleration 	= new PVector( 0, 0 );
    	}
    	
    	protected void update() {
    		velocity.add(acceleration);
    		velocity.limit(maxSpeed*2);
    		location.add(velocity);
    		acceleration.mult(0);
    	}
    
    	private PVector steer( PVector _target, boolean _slowdown ) {
    		PVector steer;
    		PVector desired = PVector.sub( _target, location );//target minus location now
    		float dist = desired.mag();// get vector length
    		if ( dist > 0 ) {
    			desired.normalize();//danweihua vector,make the length=1
    			if ( _slowdown && dist < 60 ) {
    				desired.mult( maxSpeed * (dist / 60) );
    			}
    			else {
    				desired.mult( maxSpeed );//direction*speed
    			}
    			steer = PVector.sub( desired, velocity );
    			steer.limit( maxForce );
    		}
    		else {
    			steer =new PVector( 0, 0 );
    		}
    		return steer;
    	}
    	
    	protected void seek(PVector _target) {
    		acceleration.add( steer( _target, false ) );
    	}
    }
    

    Boid主要掌管鲤鱼的运动,其中的update和代码本色中的Mover类很相似,由位置,速度,加速度和力的层层累加完成当前时刻鲤鱼位置的计算,不同的是鲤鱼的速度有最大上限,此处最大上限为定义的最大速度(maxspeed)的两倍,原因在下面再解释。这个类被创建时,会定义最初位置,最大速度与最大力并给予一个随机的初始速度。
    下面的seek与steer函数则是控制鱼类向鼠标移动的关键,steer函数接收目标位置target(slowdown参数没用到不用管),用target减去当前位置location得到运动需要的向量desired,单位化这个向量,之后将它乘以初始最大速度,就得到了所需速度(包括方向),用所需速度减去目前速度,得到所需加速度,因为此处不计重量因此用最大力来约束这个加速度后,就可以得到最终的所需加速度。使用seek函数接收目标即可更新当前加速度,成功完成导向。seek函数与代码本色中的自制智能体有关。

    Fish类继承了Boid类,而Flagellum类主要用于确定每一时刻的鲤鱼各个部分的位置与形状,在Fish类中定义了五个Flagellum类:身体,两半尾巴和两个鱼鳍,Fish类中的render函数负责绘制整个鲤鱼,这些部分我粗略看了之后没怎看懂,后来也没有更多时间 细细看了,有兴趣的朋友可以去下了源码研究研究。Fish的update函数中这一部分承接上文实现鲤鱼的游动:

    if(mousePosition.x != mousePositionOld.x ||mousePosition.y != mousePositionOld.y)
                 seek(mousePosition);//move to the mouse but some bugs...
           mousePositionOld = mousePosition;
    

    一般鼠标停留在某处不动后鲤鱼就会朝一个固定方向游动,游出画面后经由checkboders函数再从另一边游出,不过我发现如果鼠标快速在一个位置附近晃动就会出现鲤鱼停住的bug。

    最后在主文件test中创建Fish类就可以实现第一个功能了。

    Fish fish;
    PImage p;
    public void setup() {
      smooth();
      size(1400, 900);
      fish=new Fish(new PVector(700,50),3,5);
      frameRate(45); 
      p=loadImage("1.png");
    }
    
    void drawBackground()
    {
      image(p,0,0);
    }
    
    public void draw() {
      drawBackground();
      fish.render();
      fish.update();
    
    }
    
    public void mouseMoved() {
        PVector mousePosition = new PVector(mouseX, mouseY);
        fish.setMousePosition(mousePosition);
    }
    

    2.鼠标点击后施加力做起来还是挺简单的,在Boid里加入两个函数:

    	public void applyForce() {
        PVector f = velocity;
        f.normalize();
        f.mult(10);
        acceleration.add(f);
      }
      
      public void deleteForce() {
         velocity.normalize();
         velocity.mult(maxSpeed);
      }
    

    在test的draw中加入以下:

      if(mousePressed)
      {
        fish.applyForce();
        PVector mousePosition = new PVector(mouseX, mouseY);
        fish.setMousePosition(mousePosition);
      }
      else
      {
        fish.deleteForce();
      }
    

    鼠标点击后施加力,由于赋予鲤鱼的初始速度为maxspeed,所以上文中曾提到在Boid的update中给速度增加了限制,为两倍的maxspeed,施加力后鲤鱼加速到最大速度后就会匀速游动,松开鼠标则速度变回初始速度。

    3.这一部分要用到粒子系统,基础的粒子类在代码本色里是有的:

    class Particle {
      PVector position;
      PVector velocity;
      PVector acceleration;
      float lifespan;
    
      Particle(PVector l) {
        acceleration = new PVector(0, 0.05);
        velocity = new PVector(random(-1, 1), random(-1, 0));
        position = new PVector (l.x, l.y);
        lifespan = 255.0;
      }
      void run() {
        update();
        display();
      }
      void update() {
        velocity.add(acceleration);
        position.add(velocity);
        acceleration.mult(0);
      }
      void display() {
      }
      boolean isDead() {
        if (lifespan < 0.0) {
          return true;
        } 
        else {
          return false;
        }
      }
    }
    

    不过我虽然最后用到的三类粒子都继承了这个初类,但基本都重写一遍了所有变量和函数…这个就权当参考。
    泡泡类:

    class Particle1 extends Particle
    {
      final static float MAX_SPEED = 0.1;
      PVector vel = new PVector(random(-MAX_SPEED, MAX_SPEED), random(-MAX_SPEED, MAX_SPEED));
      PVector acc = new PVector(0, 0);
      PVector pos;
      float mass = random(1, 2);
      float size = mass*random(3,4);
      int lifespan = 255;
      color c;
      float wei;
      Particle1(PVector p)
      {
        super(p);
        pos = new PVector (p.x, p.y);
        acc = new PVector (random(0.1, 1.5), 0);
        if(random(0,1)<0.5)
           c=#ffffff;
        else
           c=#1E90FF;
        wei=random(1,3);
      }
      public void update()
      {
        vel.add(acc); 
        pos.add(vel); 
        acc.mult(0);
        size += 0.05; 
        lifespan=lifespan-2;
      }
      public void applyForce(PVector force) 
      {
        PVector f = PVector.div(force, mass);
        acc.add(f);
      }
      public void display()
      {
        pushMatrix();
        noFill();
        strokeWeight(wei);
        stroke(c,lifespan);
        ellipse(pos.x, pos.y, size * 4, size * 4);
        popMatrix();
      }
      
    }
    

    其中比较重要的是随机定义泡泡的质量和大小,大小部分由质量决定,随时间泡泡大小会慢慢变大。Update函数更新位置,display函数绘制粒子,之后就是粒子系统的类:

    import java.util.Iterator;
    class ParticleSystem1
    {
      ArrayList<Particle1> particles = new ArrayList<Particle1>();
      void update()
      {
        Iterator<Particle1> i = particles.iterator();
        while (i.hasNext()) {
          Particle1 p = i.next();
          if (p.pos.x > width || p.pos.x < 0) {
            i.remove();
            continue;
          } else if (p.pos.y > height || p.pos.y < 0) {
            i.remove();
            continue;
          }
          p.applyForce(new PVector(random(-1,1),0));
          p.applyForce(new PVector(0,(p.mass-p.size/3)/3));
          p.update();
          if (p.isDead()) {
            i.remove();  
          } else {
            p.display();
          }
        }
      }
    }
    

    这其中重要的是力的施加,一个是随机的左右力让泡泡晃动,另一个就是模拟浮力减去重力,当然为了实现比较良好的效果,力的设计就不太严谨,其次还有当泡泡运动到画面之外或生命到期时就从系统中除去这个粒子。
    在test中实现泡泡效果也很简单:

    ParticleSystem1 system = new ParticleSystem1();
    system.particles.add(new Particle1(new PVector(fish.location.x-5*fish.velocity.x, fish.location.y-5*fish.velocity.y)));
    system.update();
    

    4.出现鱼食也是利用粒子系统,基本架构和前面一样我就不解释贴代码了,鱼食是一个个出现的,同一时间只有一个,鱼食出现的地方会有简单的波纹,鱼食在原地一段时间后会移动并缩小。

    之后吃到鱼食绘制花朵这个想法来源与我对游戏《鲤》里莲花的印象,最后选择绘制花朵张开的动态效果。同样是利用粒子系统,其中比较重要的部分就是display绘制函数。

    pushMatrix();
      fill(255);
      stroke(255,192,200);
      strokeWeight(5);
      translate(pos.x, pos.y);
      scale(0.5);
      ellipse(0,0,120, 120);
      rotate(2*angle);
      for (int i=0; i<16; i++) {
      pushMatrix();
      float i0=30;
      rotate(i* TWO_PI/16);
      translate(0, i0);
      ellipse(0, 0, 30, 30);
      rotate(radians(angle));
      noFill();
      stroke(255,192,200);
      beginShape();
      vertex(0,0);
      bezierVertex(10,50,30,90,100,100);
      bezierVertex(90,30,50,10,0,0);
      endShape();
      popMatrix();  
      }
      if(angle<150*PI)
         angle+=speed;
      else
         ;
      popMatrix();
    

    其中angle的初始大小和speed的大小以及第一个rotate用于控制整朵花的动画幅度与速度(参数都是改来改去调到合适为止没多大深意),第一个ellipse绘制花心的圆,之后的循环用来绘制围绕花心的十六片花瓣,每一片是用自定义图形设计的花瓣形状,使用循环每次绘制后装过一定角度绘制下一片,循环中的ellipse在每片花瓣靠近花心的位置画一个圆,其中i0是指每次将坐标轴转到一片花瓣在花心的位置时,在离y轴30的距离处开始绘制花瓣,rotate(radians(angle))用来控制花瓣总体的转向,会形成花瓣张开的效果。
    在test中简单地判断鲤鱼是否碰到鱼食,出现花并清空鱼食的寿命:

    if((Math.abs(fish.location.x-foodnow.pos.x)<20)&&(Math.abs(fish.location.y-foodnow.pos.y)<20)&&(foodnow.lifespan>0))
      {
        foodnow.lifespan=0;
        flower.particles.add(new Particle3(new PVector(foodnow.pos.x, foodnow.pos.y)));
      }
    

    5.鱼的颜色加深实现起来很简单,每次判断吃到鱼食时改变鱼的颜色就行。

    6.最后是一个简单的文字提示和特效,鱼儿最终变为红色时会改变最上方的文字,初始文字和最后文字都有一点简单的动画效果。
    text类:

    class Text {
      char text;
      float homex, homey; 
      float x, y;
      float theta;
      Text(float x1, float y1, char text1) {
        homex = x = x1;
        homey = y = y1;
        text = text1;
        x = random(width);
        y = random(height);
        theta = random(TWO_PI);
      }
    
      void display() {
        textAlign(LEFT);
        pushMatrix();
        translate(x, y);
        rotate(theta);
        text(text, 0, 0);
        popMatrix();
      }
      void home() { 
        x = lerp(x, homex, 0.04);
        y = lerp(y, homey, 0.04);
        theta = lerp(theta, 0, 0.04);
      }
    }
    

    这个类使用了lerp函数来实现有趣的动画效果,首先赋予x,y和theta一个随机值,每次绘制字体将坐标轴转换到(x,y)处,且进行旋转,lerp函数使得x和y不断向homex和homey(也就是字体最终应该在的位置)靠近,角度也从随机值向0靠近,lerp函数最后一个参数决定每次靠近多少。

    总结

    程序参考了代码本色中一、二、四、六章的功能,原本想要实现很多游戏方法,但是最后只实现了一点点,而且还有很多细节没有完善,不过花了很多时间来研究借鉴的代码与代码本色上的内容,也做过很多尝试,有失败也有成功,算是勉强符合了作业要求,学到了一些东西。以后若有机会我还会把这个小游戏完善的更好,之后再上传到网站上展示,目前还是过于简单。

    参考资料

    1.鲤鱼游动:
    项目运行页面:http://mylifeaquatic.herokuapp.com/
    github源码:https://github.com/dasl-/my-life-aquatic
    2.openprocessing:https://www.openprocessing.org/

    应用推荐

    1.【融入动画技术的交互应用】——PlayWithThePicture
    https://blog.csdn.net/qq_41616984/article/details/89737428

    与图片交互的程序具有多种新奇有趣的功能,flow功能可以选取图像的一部分并让其自由流动,papercut功能使得静止的二维图像变成一条条不断飘动剪纸,赋予了图像生命。操作界面清晰易懂,制作者将多种技术相互融合,实现了自己追求的效果,让读者不由期待更加完善的功能。

    2.交互应用 | 音乐坊
    https://mp.weixin.qq.com/s?__biz=MzU4ODc2OTUyNQ==&mid=2247483745&idx=1&sn=510050b6b4438482fdb25e41c0cdadbb&chksm=fdd6f0fbcaa179edd0ab7aa13b1922d4ff02b290b0871caad79a6df7306c603ff8112a3c1b5b&mpshare=1&scene=23&srcid=#rd

    音乐可视化应用,点击屏幕不同位置可以产生多种多样的不同形状音符,同时发出不同类的声音,创建平板和小球相互碰撞后会发出鼓点的声音。程序胜在交互方式自由度高,使用者可以随心所欲创建音符,而且画面清新优美,看了介绍就忍不住想去试一试。

    3.用Processing制作一个「生态瓶」
    https://zhuanlan.zhihu.com/p/64726213

    推荐这一篇主要是因为应用的创意非常有趣,使用者可以主动设计一个简单的生态系统,控制系统中三个物种的数量,然后观察最终得到的结果。我也曾经在生物课上制作过简易的生态瓶,因此觉得这个作品不仅仅具有娱乐价值,加以完善后会有很好的教育作用。

    展开全文
  • 基于Processing动画交互

    千次阅读 多人点赞 2019-04-25 11:25:41
    基于processing动画交互基本介绍总览结果分部设计及源代码1、 添加字体2、球随鼠标3、两个对象之间的引力4、小型粒子系统心得想法 基本介绍 大致看了《代码本色》这本书之后,在原有的编程经验的基础上,对于在...

    基本介绍

    大致看了《代码本色》这本书之后,在原有的编程经验的基础上,对于在processing中添加交互有了心得认识,于是按照老师要求,写了一个简单的动画交互系统。
    整个系统运用了《代码本色》中力、震荡、粒子系统三大章,生成了各自独立的三个小场景,通过键盘的交互在三个场景之间不停转换。
    最主要的就是setup()函数和draw()函数,下面会放到部分setup()函数,draw()函数我写的很简单:

    void draw() 
    {
      background(0);
      textSize(150);
      text("Welcome to my little world",100,300);
      
      if (keyPressed)
      {
        if (key == '1')
        {
          sence1();
        }
        if (key == '2')
        {
          sence2();
        }
        if (key == '3')
        {
          sence3();
        }
      }
    }
    

    一个很简单的键盘交互,因为每个小场景都对应了自己的draw(),所以在这里直接把各自的draw()改掉了。

    总览结果

    首先,进入界面时有一个自己的标题,由于processing的交互特点,然后按下键盘‘1’是对应的第一个场景,但是一定要长按!这个纠结功能让我纠结了一回儿:
    在这里插入图片描述
    不按任何键的时候,会继续出现“welcome to my little world”字样,但是由于系统已经运行过了,字体的颜色跟着上一帧生成的颜色同步:
    在这里插入图片描述
    长按‘2’对应第二个场景:
    在这里插入图片描述
    长按‘3’对应第三个场景:
    在这里插入图片描述

    分部设计及源代码

    1、 添加字体

    在程序运行开始,先展示了动画系统的标题:“Welcome to my little world”,字体是电脑里下载过的ttf文件,这部分的代码很简单,添加字体只是给系统一个装饰。
    在这里插入图片描述

    void setup()
    {
      PFont myfont;
      myfont = createFont("CHILLER.TTF",64,false);
      textFont(myfont);
    }
    void draw()
    {
      textSize(150);
      text("Welcome to my little world",100,300);
    }
    

    2、球随鼠标

    《代码本色》的第二章讲述了力的效果,在这里让鼠标(mouseX,mouseY)对球有一个吸引力,addForce(particles[i].attractTo(mouseX, mouseY)。让球跟着随机生成的质量大小改变半径,限制速度为4,不叠加重力,没有摩擦力等阻力,在每一帧中把加速度设为0。一边向着鼠标移动一边自转。
    在这里插入图片描述

    void setup()
    {
      int n = 30;
      particles = new Particle[n];
      for (int i = 0; i < n; i++) 
      {
        PVector p = new PVector(random(0, width), random(0, height));
        particles[i] = new Particle(p);
      }
    }
    
    Particle[] particles;
    
    void sence1()
    {
      int n = 30;
      background(0);
      for (int i = 0; i < n; i++) 
      {
        particles[i].addForce(particles[i].attractTo(mouseX, mouseY));
        particles[i].run();
      }
    }
    
    class Particle 
    {
      PVector acc, vel, pos;
      float mass, incr, ang;
    
      Particle(PVector p) 
      {
        pos = p.get();
        acc =  new PVector();
        vel = new PVector();
        mass = random(.2, 2);
        ang = 0;
        incr = random(-.001, .001);
       
      }
    
      void run() 
      {
        update();
        render();
      }
    
      void update() 
      {
        vel.add(acc);
        vel.limit(4);
        pos.add(vel);
        acc.mult(0);
      }
    
      void render() 
      {
        float r = random(255);
        float g = random(255);
        float b = random(255);
        rectMode(CENTER);
        fill(200,r,g,b);
        stroke(255);
        strokeWeight(1);
    
        ang += incr;
        pushMatrix();
        translate(pos.x, pos.y);
        rotate(degrees(ang));
        ellipse(0, 0, mass*25, mass*25);
        popMatrix();
      }
    
      void addForce(PVector force) 
      {
        PVector f = PVector.div(force, mass);
        acc.add(f);
      }
      PVector attractTo(float x, float y) 
      {
        PVector mousePos = new PVector(x, y);
        PVector dir = PVector.sub(mousePos, pos);
        float dist = dir.mag();
        dist = constrain(dist, 15, 25);
        dir.normalize();
        float f = (30*mass)/(dist*dist);
        dir.mult(f);
        return dir;
      }
    }
    

    3、两个对象之间的引力

    其实大体上看,如果把1中的鼠标看做一个独立的对象,一团球粒子看做另一个独立的对象,就是2的实现结果,但是2用了另一种方法,并不是给系统添加引力,而是记录两个对象的位置,其中一个对象的位置即鼠标的位置,不停地计算两个对象之间的距离,采用循环的方法,画点。而两个对象之间不会完全重合,距离足够小时,一个对象绕着另一个做一个自定义的sin、cos函数运动。设置了透明度,让对象的运动看起来有影子的感觉。
    在这里插入图片描述

    int step = 24;
    int margin = 50;
    
    void sence2()
    {
      background(0);
      strokeWeight(sqrt(2));
      stroke(255);
      fill(255,30);
      
      int mx = mouseX;
      int my = mouseY;
      float cx = cos(radians(frameCount))*width/3 +width/3;
      float cy = sin(radians(frameCount))*height/3 +height/3;
    
      for (int aa=step/2-margin; aa<width+margin; aa+=step) 
      {
        beginShape();
        for (int bb=step/2-margin; bb<height+margin; bb+=step) 
        {
          float dism = dist(mx, my, aa, bb);
          float disc = dist(cx, cy, aa, bb);
          float x1=aa-((aa-cx)/disc + (aa-mx)/dism)*60;
          float y1=bb-((bb-cy)/disc + (bb-my)/dism)*60;
          curveVertex(x1, y1);
        }
        endShape();
      }
    
      for (int bb=step/2-margin; bb<height+margin; bb+=step) 
      {
        beginShape();
        for (int aa=step/2-margin; aa<width+margin; aa+=step) 
        {
          float dism = dist(mx, my, aa, bb);
          float disc = dist(cx, cy, aa, bb);
          float x1=aa-((aa-cx)/disc + (aa-mx)/dism)*60;
          float y1=bb-((bb-cy)/disc + (bb-my)/dism)*60;
          curveVertex(x1, y1);
        }
        endShape();
      }
    }
    

    4、小型粒子系统

    生成随机颜色的原型,上升到一定范围的随机高度再降落,一个简单的粒子系统,展示出来有一种烟花绽放的效果。系统有两个类,记录粒子的运动情况,重力,颜色,大小等基本参数,当粒子运动出屏幕时,就把该粒子删除,继续生成新的粒子。
    在这里插入图片描述

    void setup()
    {
      partList = new ArrayList<Pparticle>();
      schrapnel = new ArrayList<Scrap>();
      for (int i = 0; i < NUMPARTICLES; i++) 
      {
        createParticle();
      }
    }
    float rr = random(255);
    float gg = random(255);
    float bb = random(255);
    ArrayList<Pparticle> partList;
    ArrayList<Scrap> schrapnel;
    float GRAV = .1;
    PVector grav = new PVector(0, GRAV);
    int NUMPARTICLES = 20;
    void sence3() 
    {
      background(0);
      noFill();
      noStroke();
      displayPart();
      displaySch();
    }
    void createParticle() 
    {
      PVector pos = new PVector(random(width), height);
      float tempDir = ((width/2 - pos.x) > 0) ? 1 : -1;  
      PVector vel = new PVector((dist(width/2, 0, pos.x, 0) * tempDir)/200, random(-10, -5));
      partList.add(new Pparticle(pos, vel, grav, 5, color(50)));
    }
    void displayPart()
    {
      for (int i = 0; i < partList.size(); i++) 
      {
        Pparticle temp = partList.get(i);
        if (temp.atApex()) 
        {
          temp.explode();
          partList.remove(i);
          createParticle();
        }
        temp.display();
      }
    }
    void displaySch()
    {
      for (int i = 0; i < schrapnel.size(); i++) 
      {
        Scrap temp = schrapnel.get(i);    
        temp.display(); 
        if (temp.offScreen()) 
        { 
          schrapnel.remove(i);
        }
      }
    }
    class Pparticle 
    {
      PVector ppos, vvel, ggrav;
      int size;
      color col, schCol;
      Pparticle(PVector pos_, PVector vel_, PVector grav_, int size_, color col_) 
      {
        ppos = pos_;
        vvel = vel_;
        ggrav = grav_;
        size = size_;
        col = col_;
        schCol = color(int(random(0, 255)), int(random(0, 255)), int(random(0, 255)));
      }
      void display() 
      {
        //fill(180,col);
        fill(rr,gg,bb);
        calculate();
        ellipse(ppos.x, ppos.y, size, size);
      }
      void calculate() 
      {
        ppos.add(vvel);
        vvel.add(ggrav);
      }
      void explode() 
      {    
        for (int i = 0; i < 50; i++) 
        {
          createSchr();
        }
      }
      void createSchr() 
      {
        PVector tempPos = new PVector(ppos.x, ppos.y);
        PVector tempVel = new PVector(random(-2, 2), random(-4, 0));
        schrapnel.add(new Scrap(tempPos, tempVel, ggrav, 2, schCol));
      }
      boolean atApex() 
      {
        return(vvel.y > 0 && (vvel.y - ggrav.y) < 0);
      }
      boolean offScreen() 
      {
        return(ppos.y > height);
      }
    }
    class Scrap 
    {
      PVector pppos, vvvel, gggrav;
      int size;
      color col, schCol;
      boolean fade;
      int life = 0;
      Scrap(PVector pos_, PVector vel_, PVector grav_, int size_, color col_) 
      {
        pppos = pos_;
        vvvel = vel_;
        gggrav = grav_;
        size = size_;
        col = col_;  
      }
      void display()
      {
       calculate();
       fill(200, red(col) - life * 2, blue(col) - life * 2, green(col) - life * 2);
       //fill(r,g,b);
       ellipse(pppos.x, pppos.y, size + 2, size + 2);   
      }  
      void calculate()
      {
       pppos.add(vvvel);
       vvvel.add(gggrav);
       life++; 
      }
      boolean offScreen()
      {
       return(pppos.y > height); 
      }
    }
    

    5、心得想法

    这里是博主的一点心得碎碎念,可以跳过啦~
    在做这个系统(其实是一门课的结课作业)时,想了很久关于自己要做什么,于是产生了很多写到一半就放弃的文件。
    在这里插入图片描述
    归根结底就是自己能力有限,在这里自我反思,为什么可以想却做不到,有时候走在路上也在想某个功能应该怎么实现,后来发现了processing网站,其实早应该发现了,里面有很多很好地例子,最感兴趣的其实是粒子系统生成的时钟,尝试了三个小时发现自己实现不了,无奈放弃。
    这次的三个案例也是反反复复修改了很久,比如说全局变量命名重复、类的命名和使用,setup和draw函数里最终应该放什么代码,转到另一个场景时没有重置背景……一系列问题,简单的或复杂的,经过不停地搜索,终于一点一点解决了。
    对于字体是后来才想起来加上去,之前的实验中没有做过这种,搜索怎么添加字体之后发现其实很简单,添加完之后又想,为什么不直接在ps里做一张图导入呢,只需两行,运行之后发现,忘记给字体添加颜色,后来跟系统同步了,算是一个小的柳暗花明吧。
    这次实验收获很大,不仅仅是关于代码的学习,更重要的是自己一点一点解决问题的过程,有时候产生很弱智的问题,可那也是自己写出来的。还有根据自己的想法,一步一步搜索实现的过程,很累但是很有成就感。
    参考文献
    《代码本色》 网上有很多PDF链接,这里直接是老师发的>_<
    https://processing.org/ 这绝对是个宝藏网站,三个场景都是在这里发现并且写出来修改的

    展开全文
  • processing几种简单动画

    万次阅读 多人点赞 2018-11-27 11:14:10
    这是我用processing写出的扩散效果 package Exercise; import processing.core.PApplet; import processing.core.PGraphics; import processing.core.PImage; /** * @author Administrator * */ public class ...

    环形扩散

    这是我用processing写出的扩散效果
    扩散渐变

    package Exercise;
    import processing.core.PApplet;
    import processing.core.PGraphics;
    import processing.core.PImage;
    
    /**
     * @author Administrator
     *
     */
    public class Animation {
    	//声明全局变量
    	PApplet zoomApplet;
    	
    	 扩散的圆圈
    	PImage photo;
    	int animateWidth;
    	int animateHeigth;
    	int centerX;
    	int centerY;
    	float radius;
    	
    	
    	private int progressive = 1;
    	private int circleAlpha = 255;
    	
    	//构造函数
    	public Animation(PApplet zoomApplet,int animateWidth,int animateHeigth,int centerX,int centerY) {
    		this.zoomApplet = zoomApplet;
    		this.animateWidth = animateWidth;
    		this.animateHeigth = animateHeigth;
    		this.centerX = centerX;
    		this.centerY = centerY;
    	}
    
    	
    	//镭射线效果
    	float originRadius;
    	float secondRadius;
    	public void setupDiffusionRadiumRays(PGraphics zoomGraphics) {
    		
    		//photo = zoomApplet.loadImage("Resources\\Images\\3.jpg");
    		originRadius = radius;
    		secondRadius = radius-animateWidth/4;
    	}
    	public void drawDiffusionRadiumRays(PGraphics zoomGraphics) {
    		
    		zoomGraphics.noFill();
    		//zoomGraphics.image(photo, 0, 0);
    		radius += 1;
    		secondRadius += 1;
    		float pointX;
    		float pointY;
    		zoomGraphics.strokeWeight(10);
    		for(int i=0;i<180;i++)
    		{
    			int angle = i*2;
    			zoomGraphics.stroke(zoomGraphics.color(angle,180,60));
    			float originX = centerX + PApplet.cos((float) (angle*Math.PI/180))*radius;
    			float originY = centerY + PApplet.sin((float) (angle*Math.PI/180))*radius;
    			pointX = centerX + PApplet.cos((float) (angle*Math.PI/180))*(radius - 20);
    			pointY = centerY + PApplet.sin((float) (angle*Math.PI/180))*(radius - 20);
    			zoomGraphics.line(originX, originY, pointX, pointY);
    			if (secondRadius>0) {
    				float pointX1 = centerX + PApplet.cos((float) (angle*Math.PI/180))*(secondRadius-20);
    				float pointY1 = centerY + PApplet.sin((float) (angle*Math.PI/180))*(secondRadius-20);
    				float pointX2 = centerX + PApplet.cos((float) (angle*Math.PI/180))*secondRadius;
    				float pointY2 = centerY + PApplet.sin((float) (angle*Math.PI/180))*secondRadius;
    				zoomGraphics.line(pointX1, pointY1, pointX2, pointY2);
    			}
    		}	
    		if (radius>animateWidth/2) {
    			radius = originRadius;
    		}
    		if (secondRadius>animateWidth/2) {
    			secondRadius = originRadius;
    		}
    	}
    	
    	public float getRadius() {
    		return radius;
    	}
    
    	public void setRadius(float radius) {
    		this.radius = radius;
    	}
    	
    
    }
    

    火 焰

    这是我用processing写出的火焰效果
    火焰

    河 流

    这是我用processing写出的类似于河流的效果
    河流

    海 域

    这是我用processing写出的一片海域的效果
    海域
    以上三个是做出来的效果,下面上processing代码

    火焰

    package Exercise;
    
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.util.ArrayList;
    
    import processing.core.PApplet;
    import processing.core.PImage;
    import processing.core.PVector;
    
    public class FireApplet extends PApplet{
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	
    	//初始化自定义粒子系统类变量
    	ParticleSystem particleSystem;
    	
    	
    	//动画的初始化方法
    		public void setup()
    		{
    			size(800,800);
    			PImage image = loadImage("../Resources/Images/fire.png");
    			particleSystem = new ParticleSystem(0, new PVector(width/2,500), image);
    		}
    		//动画的绘画方法
    		public void draw()
    		{
    			background(0);
    			float dx = map((float)mouseX, 0, (float)width, (float)-0.2, (float)0.2);
    			PVector wind = new PVector(dx,0);
    			//particleSystem.applyForce(wind);
    			particleSystem.run();
    			for (int i = 0; i < 2; i++) {
    				particleSystem.addParticle();
    			}
    		}
    		
    		// TODO 创建Particle类有助于降低复杂度
    		class Particle {
    			PVector loc;
    			PVector vel;
    			PVector acc;
    			float lifespan;
    			PImage image;
    		 Particle(PVector pVector,PImage img) {
    				acc = new PVector(0,0);
    				float vx = (float) (randomGaussian()*0.3);
    				float vy = (float) (randomGaussian()*0.3 -1.0);
    				vel = new PVector(vx,vy);
    				loc = CloneSeries.clone(pVector);
    				lifespan = 100;
    				image = img;
    				
    			}
    		 void run()
    		 {
    			 update();
    			 render();
    		 }
    		 void applyForce(PVector fPVector)
    		 {
    			 acc.add(fPVector);
    		 }
    		 void update()
    		 {
    			 vel.add(acc);
    			 loc.add(vel);
    			 lifespan -= 2.5;
    			 acc.mult(0);
    		 }
    		 void render()
    		 {
    			 imageMode(CENTER);
    			 tint(255,lifespan);
    			 image(image,loc.x,loc.y);
    		 }
    		 boolean isDead()
    		 {
    			 if (lifespan<=0) {
    				return true;
    			}
    			 else
    			 {
    				 return false;
    			 }
    		 }
    		}
    		
    		// TODO 创建Particle系统类
    		class ParticleSystem
    		{
    			ArrayList<Particle>particles;
    			PVector origin;
    			PImage image;
    			
    			ParticleSystem(int num,PVector v,PImage img) {
    				particles = new ArrayList<Particle>();
    				origin = CloneSeries.clone(v);
    				image = img;
    				for(int i=0;i<num;i++)
    				{
    					particles.add(new Particle(origin, image));
    				}
    			}
    			void run()
    			{
    				for(int i=particles.size()-1;i>=0;i--)
    				{
    					Particle particle = particles.get(i);
    					particle.run();
    					if (particle.isDead()) {
    						particles.remove(i);
    					}
    				}
    			}
    			void applyForce(PVector dir)
    			{
    				for(Particle p:particles)
    				{
    					p.applyForce(dir);
    				}
    			}
    			void addParticle()
    			{
    				particles.add(new Particle(origin, image));
    			}
    		}
    		
    		 static class CloneSeries {
    		    @SuppressWarnings("unchecked")
    			public static <T extends Serializable> T clone(T obj){
    		        T cloneObj = null;
    		        try {
    		            //写入字节流
    		            ByteArrayOutputStream out = new ByteArrayOutputStream();
    		            ObjectOutputStream obs = new ObjectOutputStream(out);
    		            obs.writeObject(obj);
    		            obs.close();
    		            //分配内存,写入原始对象,生成新对象
    		            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
    		            ObjectInputStream ois = new ObjectInputStream(ios);
    		            //返回生成的新对象
    		            cloneObj = (T) ois.readObject();
    		            ois.close();
    		        } catch (Exception e) {
    		            e.printStackTrace();
    		        }
    		        return cloneObj;
    		    }
    		}
    }
    
    

    河流

    package Exercise;
    
    import java.awt.Container;
    
    import processing.core.PApplet;
    import processing.core.PGraphics;
    import processing.core.PImage;
    
    public class RiverApplet extends PApplet{
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	PGraphics riverPhics;
    	PApplet riverApplet;
    	float yoff = (float) 0.0;        // 2nd dimension of perlin noise
    	int  [] xRows;
    	int  [] yRows1;
    	int  [] yRows2;
    	PImage[] plan3DImage;
    	
    	public void setup() {
    		size(1000,1000);
    	}
    
    	public void draw() {
    		
    		//
    		clear();
    		background(color(16,120,180));
    	  fill(color(60,140,255));
    	  // We are going to draw a polygon out of the wave points
    	  beginShape();
    	  float xoff = 0;   // Option #1: 2D Noise
    	  //float xoff = yoff; // Option #2: 1D Noise
    	  // Iterate over horizontal pixels
    	  for (float x = 0; x <= width; x += 5) {
    	    // Calculate a y value according to noise, map to 
    	    float y = map(noise(xoff, yoff), 0, 1, 250,300); // Option #1: 2D Noise
    	    //float y = map(noise(xoff), 0, 1, 200,300); // Option #2: 1D Noise
    	    // Set the vertex
    	    vertex(x, y);
    	    // Increment x dimension for noise
    	    xoff += 0.05;
    	  }
    	  for (float x2 = width; x2 >=0; x2 -= 5) {
    		    // Calculate a y value according to noise, map to 
    		    float y2 = map(noise(xoff, yoff), 0, 1, 450,500); // Option #1: 2D Noise
    		    //float y = map(noise(xoff), 0, 1, 200,300); // Option #2: 1D Noise
    		    // Set the vertex
    		    vertex(x2, y2); 
    		    // Increment x dimension for noise
    		    xoff += 0.05;
    		  }
    	  // increment y dimension for noise
    	  yoff += 0.01;
    	  endShape(CLOSE);
    	  
    	}
    	
    
    

    //以上这个是使用noise()方法绘制出来的效果,这种效果很逼真,但是无法根据实际的河流坐标进行修改,所以我使用了下面的这个方法,绘制特定路线的河流,并添加河流的动画效果

    package Exercise;
    
    import java.awt.Container;
    
    import processing.core.PApplet;
    import processing.core.PGraphics;
    import processing.core.PImage;
    
    public class RiverApplet extends PApplet{
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	PGraphics riverPhics;
    	PApplet riverApplet;
    	float yoff = (float) 0.0;        // 2nd dimension of perlin noise
    	int  [] xRows;
    	int  [] yRows1;
    	int  [] yRows2;
    	PImage[] plan3DImage;
    	
    	public void setup() {
    		size(1000,1000);
    		
    	  setupRiverLines();
    	}
    
    	public void draw() {
    		
    		 riverPhics.beginDraw();
    		 riverPhics.background(102);
    		 riverPhics.stroke(255);
    		 drawRiverLines();
    		 riverPhics.endDraw();
    		 plan3DImage[0] = riverPhics.get();
    		 image(riverPhics, 100, 100);
    		 frameRate(5);
    		//
    
    	public void setupRiverLines()
    	{
    		plan3DImage = new PImage[1];
    		//background(255);
    		riverPhics = createGraphics(800, 800);
    		
    		riverPhics.background(255);
    	  xRows = new int [21];
    	  yRows1 = new int [21];
    	  yRows2 = new int [21];
    	}
    	public void drawRiverLines() {
    		
    		riverPhics.stroke(color(0));
    		riverPhics.strokeWeight(8);
    		//riverPhics.fill(75,121,199);
    		  for(int i=0;i<=20;i++)
    		  {
    			  xRows[i] = 40*i;
    			  yRows1[i] = (int) (random(100, 150) + 60);
    			  yRows2[i] = (int) (random(200, 250) + 160);
    		  }
    		  
    		  riverPhics.beginShape();
    		  
    		  for(int j=0;j<xRows.length;j++)
    		  {
    			  riverPhics.curveVertex(xRows[j], yRows1[j]);
    		  }
    		  for(int k=xRows.length;k>0;k--)
    		  {
    			  riverPhics.curveVertex(xRows[k-1], yRows2[k-1]);
    		  }
    		  riverPhics.endShape();
    		  
    	}
    
    }
    
    

    海域

    package Exercise;
    
    
    import processing.core.PApplet;
    import processing.core.PShape;
    
    public class SeaApplet extends PApplet {
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	int screenWidth = 800;
    	int screenHeigth = 800;
    	float increment = (float) 0.01;
    	int directX = -1;// X轴移动方向1\-1
    	int directY = 1;// Y轴移动方向1\-1
    	float moveMent = (float) 0.05;// 代表海面移动速度0.1--0.01之间
    	float xoff = 0;
    	float yoff = 0;
    	int  [] xRows;
    	int  [] yRows;
    	int loopNum;
    	
    	// 启动程序入口
    	public void setup() {
    		
    		size(screenWidth, screenHeigth,P2D);
    		background(15, 101, 180);
    		
    		drawShapeLine();
    		
    		fill(color(60, 140, 255));
    		stroke(0);
    	}
    
    	// 循环绘画方法
    	public void draw() {
    		
    		
    		
    		// 循环海域,绘制noise即浪花
    		xoff = yoff = increment;
    		for (int x = 0; x <= 650; x++) {
    			yoff = increment;
    			for (int y = 0; y < height; y++) {
    				float rcolor = map(noise(xoff, yoff), 0, 1, 10, 60);
    				float gcolor = map(noise(xoff, yoff), 0, 1, 80, 120);
    				float bcolor = map(noise(xoff, yoff), 0, 1, 160, 255);
    				// System.out.println("R:"+rcolor+"G:"+gcolor+"B:"+bcolor);
    				if (x<=100) {
    					set(x, y, color(rcolor, gcolor, bcolor));
    				}
    				else if (x>100&&x<=200) {
    					caculateMethod(100, 800, 250, 550);
    					boolean isIn = DownAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>200&&x<=250&&y>550) {
    					caculateMethod(100, 800, 250, 550);
    					boolean isIn = DownAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>200&&x<=250&&y<=550) {
    					caculateMethod(200, 0, 500, 80);
    					boolean isIn = UpAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>250&&x<=350&&y<=550) {
    					caculateMethod(200, 0, 500, 80);
    					boolean isIn = UpAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>250&&x<=350&&y>550) {
    					caculateMethod(350, 750, 250, 550);
    					boolean isIn = DownAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>350&&x<=500&&y<=80) {
    					caculateMethod(200, 0, 500, 80);
    					boolean isIn = UpAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>350&&x<=500&&y>80) {
    					caculateMethod(350, 750, 600, 500);
    					boolean isIn = DownAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>500&&x<=550&&y<=350) {
    					caculateMethod(500, 80, 600, 50);
    					boolean isIn = UpAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>500&&x<=550&&y>350) {
    					caculateMethod(350, 750, 600, 500);
    					boolean isIn = DownAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>550&&x<=600&&y<=80) {
    					caculateMethod(500, 80, 600, 50);
    					boolean isIn = UpAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>550&&x<=600&&y<=350&&y>80) {
    					caculateMethod(550, 350, 650, 150);
    					boolean isIn = DownAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>550&&x<=600&&y>350&&y<=500) {
    					caculateMethod(550, 350, 600, 500);
    					boolean isIn = UpAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>550&&x<=600&&y>500) {
    					caculateMethod(350, 750, 600, 500);
    					boolean isIn = DownAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>600&&x<=650&&y<=350&&y<=150) {
    					caculateMethod(600, 50, 650, 150);
    					boolean isIn = UpAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    				else if (x>600&&x<=650&&y<=350&&y>150) {
    					caculateMethod(550, 350, 650, 150);
    					boolean isIn = DownAnalysePoint(x, y);
    					if (isIn) {
    						set(x, y, color(rcolor, gcolor, bcolor));
    					}
    				}
    								
    				yoff += (0.01 * directY);
    			}
    			xoff += (0.01 * directX);
    		}
    		increment += moveMent;
    		
    		// 海岸线拐点(0,0)(200,0)(500,80)(600,50)(650,150)(550,350)(650,500)(350,750)(250,550)(100,800)(0,800)
    				// 开始绘制海域
    //		noFill();
    //				beginShape();
    //				vertex(width, 0);
    //				vertex(200, 0);
    //				vertex(500, 80);
    //				vertex(600, 50);
    //				vertex(650, 150);
    //				vertex(550, 350);
    //				vertex(600, 500);
    //				vertex(350, 750);
    //				vertex(250, 550);
    //				vertex(100, 800);
    //				vertex(width, height);
    //				endShape(CORNER);
    		// 绘画帧数
    		frameRate(20);
    		
    		
    	}
    	
    	public void drawShapeLine()
    	{
    		loopNum = 0;
    		//坐标数组
    		xRows = new int [11];
    		yRows = new int [11];
    		xRows[0] = width;
    		yRows[0] = 0;
    		xRows[1] = 200;
    		yRows[1] = 0;
    		xRows[2] = 500;
    		yRows[2] = 80;
    		xRows[3] = 600;
    		yRows[3] = 50;
    		xRows[4] = 650;
    		yRows[4] = 150;
    		xRows[5] = 550;
    		yRows[5] = 350;
    		xRows[6] = 600;
    		yRows[6] = 500;
    		xRows[7] = 350;
    		yRows[7] = 750;
    		xRows[8] = 250;
    		yRows[8] = 550;
    		xRows[9] = 100;
    		yRows[9] = height;
    		xRows[10] = width;
    		yRows[10] = height;
    		System.out.println("数组:"+xRows+yRows);
    		
    		
    		noFill();
    		stroke(color(123,123,123));
    		beginShape();
    		curveVertex(xRows[loopNum], yRows[loopNum]);
    		for(int i=loopNum;i<=10;i++)
    		{
    			curveVertex(xRows[i], yRows[i]);
    		}
    		if (loopNum>0&&loopNum<11) {
    			for(int i=0;i<loopNum;i++)
    			{
    				curveVertex(xRows[i], yRows[i]);
    			}
    			curveVertex(xRows[loopNum], yRows[loopNum]);
    		}
    		else
    		{
    			curveVertex(xRows[10], yRows[10]);
    		}
    		loopNum++;
    		if (loopNum>10) {
    			loopNum=0;
    		}
    		endShape(CLOSE);
    	}
    	double [] result;
    	public double[] caculateMethod(int x1,int y1,int x2,int y2)
    	{
    		y1 = screenHeigth-y1;
    		y2 = screenHeigth-y2;
    		result = new double[2];
    		float k,a;
    		k=(float)(y2-y1)/(x2-x1);
    		a=y2-k*x2;
    		result[0]=k;
    		result[1]=a;
    		return result;
    	}
    	public boolean UpAnalysePoint(int x,int y)
    	{
    		float resultY = 0;
    		y = screenHeigth-y;
    		if (result!=null) {
    			float k=(float) result[0];
    			float a=(float) result[1];
    			resultY=  k*x + a;
    		}
    		if (resultY>=y) {
    			return true;
    		}
    		else
    		{
    			return false;
    		}
    		
    	}
    	
    	public boolean DownAnalysePoint(int x,int y)
    	{
    		float resultY = 0;
    		y = screenHeigth-y;
    		if (result!=null) {
    			float k=(float) result[0];
    			float a=(float) result[1];
    			resultY=  k*x + a;
    		}
    		if (resultY<=y) {
    			return true;
    		}
    		else
    		{
    			return false;
    		}
    		
    	}
    	
    }
    
    

    //这个方法的核心依然是noise()。

    以上就是项目中使用到的动画效果。

    展开全文
  • Processing 状态量控制动画技巧

    千次阅读 2017-03-17 08:21:50
    Processing 状态量控制动画技巧本章介绍Processing 状态量控制动画技巧。分三个小例子供大家参考。一、状态量state控制圆缩放动画使用if语句搭配state控制量可以控制动画,如下: int ellipse_r = 100;//定义并初始...

    Processing 状态量控制动画技巧

    本章介绍Processing 状态量控制动画技巧。分三个小例子供大家参考。


    一、状态量state控制圆缩放动画

    使用if语句搭配state控制量可以控制动画,如下:
    
    int ellipse_r = 100;//定义并初始化圆的大小(直径)
    int state = 0;      //定义状态量state,缺省值0;
    
    void setup()
    {
      size(500, 500);
    }
    
    void draw()
    {
      background(0);
    
      if (state == 0)
      {
        ellipse_r ++;
      }
      if (state == 1)
      {
        ellipse_r --;
      }
      if (ellipse_r >= 250)
      {
        state = 1;
      }
      if (ellipse_r <= 50)
      {
        state = 0;
      }
      ellipse(width/2, height/2, ellipse_r, ellipse_r);
    }

    如图所示:
    这里写图片描述

    二、状态量控制红绿灯

    state状态量控制红绿灯,循环切换状态,如下:
    
    int ellipse_r = 100;//定义并初始化圆的大小(直径)
    int state = 0;      //定义状态量state,缺省值0;
    boolean FLASH = false;//闪烁开关
    int timecount;      //计时器
    float oldtime;      //过去的时刻
    void setup()
    {
      size(500, 500);
    
      oldtime = millis();
    }
    
    void draw()
    {
      UpdateState();
    
      Display();
    }
    
    void UpdateState()
    {
    
      if (millis() - oldtime >=1000)
      {
        timecount ++;
        oldtime = millis();
      }
      println(timecount);
      if (timecount <= 2)
        state = 0;
      else if (timecount > 2 && timecount <=5)
        state = 1;
      else if (timecount > 5 && timecount <=6)
        state = 2;
      else if (timecount > 6 && timecount <=8)
        state = 3;
      else if (timecount > 8)
        timecount = 0;
    
      if (state == 1)
      {
        if (second() %2 == 0)
          FLASH = true;
        else
          FLASH = false;
      }
    }
    
    void Display()
    {
      background(0);
    
      switch(state)
      {
      case 0:        //绿灯亮
        noStroke();
        fill(0, 250, 0);
        ellipse(width/2-200, height/2, 100, 100);
        break;
      case 1:        //绿灯闪烁
        noStroke();
        fill(0, 250, 0);
        if (FLASH)
          ellipse(width/2-200, height/2, 100, 100);
        break;
      case 2:        //黄灯亮
        noStroke();
        fill(255, 210, 0);
        ellipse(width/2, height/2, 100, 100);
        break;
      case 3:        //红灯亮
        noStroke();
        fill(250, 0, 0);
        ellipse(width/2+200, height/2, 100, 100);
        break;
      }
    }
    

    如图:
    这里写图片描述

    三、状态量控制矩阵

    使用状态量控制LED灯阵;
    
    ArrayList<LED> ledlist;      //定义动态列表(也可用普通列表)
    int ledwidth = 75;          
    boolean ispressed = false;
    
    void setup()
    {
      size(500, 500);
    
      ledlist = new ArrayList<LED>();
    
      LED led1 = new LED(width/2-ledwidth-100, height/2-ledwidth-100, ledwidth);
      LED led2 = new LED(width/2-ledwidth-100, height/2, ledwidth);
      LED led3 = new LED(width/2-ledwidth-100, height/2+ledwidth+100, ledwidth);
      LED led4 = new LED(width/2, height/2-ledwidth-100, ledwidth);
      LED led5 = new LED(width/2, height/2, ledwidth);
      LED led6 = new LED(width/2, height/2+ledwidth+100, ledwidth);
      LED led7 = new LED(width/2+ledwidth+100, height/2-ledwidth-100, ledwidth);
      LED led8 = new LED(width/2+ledwidth+100, height/2, ledwidth);
      LED led9 = new LED(width/2+ledwidth+100, height/2+ledwidth+100, ledwidth);
    
      ledlist.add(led1);
      ledlist.add(led2);
      ledlist.add(led3);
      ledlist.add(led4);
      ledlist.add(led5);
      ledlist.add(led6);
      ledlist.add(led7);
      ledlist.add(led8);
      ledlist.add(led9);
    }
    
    void draw()
    {
      background(0);
    
      for(int i=0;i < ledlist.size(); i++)        //遍历绘画函数
      {
        LED led = ledlist.get(i);
        led.draw();
      }
    }
    
    void mousePressed()
    {
        for(int i=0;i < ledlist.size(); i++)
      {
        LED led = ledlist.get(i);
        led.update();                              //当鼠标点击时更新状态
      }
    }
    
    LED类定义:
    
    class LED {
      int x;//X轴向位置
      int y;//Y轴线位置
      int state;//状态量
      int k;//开关变量(参考本节第一个小例子)
      int w;//大小
      int degs;//角度
      int c;//颜色(色相值)
      LED(int x_, int y_, int w_) {    //构造函数初始化变量
        x = x_;
        y = y_;
        w = w_;
        c = (int)random(0,360);        //初始化随机赋颜色
        state = 0;
        k = 0;
        degs = 0;
      }
      void update()                    //检测鼠标是否悬停在方框内
      {
        if (overRect(x-w/2, y-w/2, w, w))
        {
          state ++;                    //鼠标点击,三种状态循环切换
          if (state >= 3)
          {
            state = 0;
          }
        } 
      }
      void draw()
      {
        colorMode(HSB,360,100,100);    //使用HSB颜色模型
        if (state == 0)                //第一种情况,呈现原有状态
        {
          pushMatrix();
          translate(x, y);
          rotate(radians(degs));
          fill(c,100,100);
          noStroke();
          rectMode(CENTER);
          rect(0, 0, w, w);
          popMatrix();
        } else if (state == 1)          //第二种情况,旋转方框
        {
          pushMatrix();
          translate(x, y);
          rotate(radians(++degs));
          fill(c,100,100);
          noStroke();
          rectMode(CENTER);
          rect(0, 0, w, w);
          popMatrix();
        } else if (state == 2)            //第三种情况,改变颜色
        {
          pushMatrix();
          translate(x, y);
          rotate(radians(degs));
          if (k == 0)
            c ++;
          if (k == 1)
            c --;
          if (c <=0)
          {
            c = 0;
            k = 0;
          }
          if (c >= 360)
          {
            c = 360;
            k = 1;
          }
          fill(c,100,100);
          noStroke();
          rectMode(CENTER);
          rect(0, 0, w, w);
          popMatrix();
        }
      }
      boolean overRect(int x, int y, int width, int height) {
        if (mouseX >= x && mouseX <= x+width && 
          mouseY >= y && mouseY <= y+height) {
          return true;
        } else {
          return false;
        }
      }
    }
    
    如图:
    

    这里写图片描述

    这里写图片描述

    总结:
        把更新数据和绘画渲染的工作分开来处理,在更新数据的模块里相应的设置state状态所控制的内容,然后在绘画渲染的模块里检索state的值,相应的更改绘画的模式或者属性。
    
    展开全文
  • 打开Processing,Ctrl+R运行. 运行效果 : class myRect { float x,y; float r,a;//banjing secai bianhua myRect(float x, float y, float r,float a) { this.x = x; this.y = y; this.r = r; this.a ...
  • 利用粒子来模仿 AE 的文字动画特效 , 包括改变文字大小/旋转方向/重力作用/随机游走等动画
  • 融入动画技术的交互应用 根据《代码本色》书本内容前四章实现了本次实验项目 1.Perlin噪声实现随机游走 每个小球的移动都根据受其速度影响,同时速度由受加速度影响,为了实现每个小球的运动有明显区别...
  • Processing-日常3】等待动画1

    千次阅读 2018-03-30 13:08:47
    今天我们用Processing来模拟一下! 先来看一下最后的效果: 分析 首先分析一下这个效果是由哪些元素构成。 1. 有一个基本图形,复制了好多分。 2. 每一个图形按照一种特定的运动规律在做动画。 3. 动画...
  • 读《数据可视化之美》时看到编程语言Processing这么个东西,于是下载过来简单使用了下。 下载地址:...下面是一个的时钟动画的例子,代码如下: [html] view plaincopy
  •  关于物体控制的程序框架 ...shapes3d库有专职动画的包,但其内容实现我也不太清楚,猜测是把对象的显示和动画行为分开到不同的类中实现的,由此我想如果在我自己的Processing程序中如何做到在显示对

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 222
精华内容 88
关键字:

processing动画