Processing 009 一个复杂点的例子,OOP实现屏幕碰撞小球

Processing 009 一个复杂点的例子,OOP实现屏幕碰撞小球

1 processing 中的面向对象编程

基本上和 java 的语法一致,例如

class Car{
	String name;
	int price;
	public Car(String name, int price){
		this.name = name;
		this.price = price;
	}
	
	public void printInfo(){
		println("name:" + this.name);
		println("price:" + this.price);
	}
}

以上是一个非常简单的例子,接下来我门实现真实的例子

2 面向对象实现屏幕玻璃球碰撞

2.1 实现 MyCircle 类:

2.1.1 MyCircle 类代码
class MyCircle {
  float x, y, r;
  float vx, vy;
  float H;

  public MyCircle(float x, float y, float r) {
    this.x = x;
    this.y = y;
    this.r = r;
    this.vx = random(0.5);
    this.vy = random(0.5);
    this.H = random(255);
  }

  public void draw() {
    fill(H, 255, 255, 10);
    ellipse(this.x, this.y, 2 * this.r, 2 * this.r);
  }

  public void update() {
    this.x += this.vx;
    this.y += this.vy;
  }
  
  public void checkEdge(){
     if(this.x <= r){
       this.x = r;
       this.vx = -this.vx;
     }
     
     if(this.x + r >= width){
       this.x = width - r;
       this.vx = -this.vx;
     }
     
     if(this.y <= r){
       this.y = r;
       this.vy = -this.vy;
     }
     
     if(this.y + r >= height){
       this.y = height - r;
       this.vy = -this.vy;
     }
  }
  
  public void checkOther(MyCircle o){
      float dis = dist(this.x, this.y, o.x, o.y);
      if(dis <= r + o.r){
        float dirx = o.x - this.x;
        float diry = o.y - this.y;
        float D = sqrt(sq(dirx) + sq(diry));
        dirx /= D;
        diry /= D;
        float F = sqrt(sq(this.vx) + sq(this.vy));
        this.vx = - F * dirx;
        this.vy = - F * diry;
        F = sqrt(sq(o.vx) + sq(o.vy));
        o.vx = F * dirx;
        o.vy = F * diry;
      }
  }
}
2.1.2 MyCircle 类功能简介

MyCircle 类主要有圆心坐标个和半径 x, y, r 速度vx, vy, 还有一个色度 H,表示圆的颜色。
在构造方法中,直接传入 x, y, r, 而 vx,vy, H 随机产生,所以产生的圆颜色和大小随机。

接下来两个方法

// 绘制自身, 注意用 HSB 模式绘制,不透明度设置较低,作出透明效果
public void draw() {
    fill(H, 255, 255, 10); // 
    ellipse(this.x, this.y, 2 * this.r, 2 * this.r);
  }
// 根据位置和速度更新自己的位置信息
  public void update() {
    this.x += this.vx;
    this.y += this.vy;
  }

这两个方法比较简单,主要是实现位置更新和绘制。但是球可能直接跑出屏幕范围,所以要检查一下:

public void checkEdge(){
	// 检查左侧是否出界
     if(this.x <= r){
       this.x = r;
       this.vx = -this.vx;
     }
     // 检查右侧是否出界
     if(this.x + r >= width){
       this.x = width - r;
       this.vx = -this.vx;
     }
     // 检查上侧是否出界
     if(this.y <= r){
       this.y = r;
       this.vy = -this.vy;
     }
     // 检查下侧是否出界
     if(this.y + r >= height){
       this.y = height - r;
       this.vy = -this.vy;
     }
  }

检查四个边缘是否出界,如果出界,对应的速度方向相反,实现反弹效果。

接下来是检查球和其它球之间是否碰撞,碰撞之后的速度处理,这部分比较关键。

public void checkOther(MyCircle o){
	  // 获取两个球的球心之间的距离
      float dis = dist(this.x, this.y, o.x, o.y);
      // 如果距离小于半径和即相碰了
      if(dis <= r + o.r){ // 处理碰撞结果
      	// 计算圆心连线方向
        float dirx = o.x - this.x;
        float diry = o.y - this.y;
        // 归一化方向
        float D = sqrt(sq(dirx) + sq(diry));
        dirx /= D;
        diry /= D;
        //小球的位置大小不变、方向和位置圆心连线方向相反
        float F = sqrt(sq(this.vx) + sq(this.vy));
        this.vx = - F * dirx;
        this.vy = - F * diry;
        F = sqrt(sq(o.vx) + sq(o.vy));
        o.vx = F * dirx;
        o.vy = F * diry;
      }
  }

2.2 CircleManager 类

2.2.1 代码
class CircleManager {
  int N, Rmax, Rmin;
  MyCircle[] circles;
  
  public boolean generate(int n){
    float x = random(width);
    float y = random(height);
    float r = random(Rmin, Rmax);
    
    if(x - r < 0 || x + r > width ||  y - r < 0 || y + r > height)
        return false;
      
    for(int i = 0; i < n; i++){
        if(dist(x, y, circles[i].x, circles[i].y) < r + circles[i].r)
             return false;
    }
    
    circles[n] = new MyCircle(x, y, r);
    return true;
  }
  
  
  public void init(){
    circles = new MyCircle[this.N];
    
    for(int i = 0;i < N;i++){
        while(!generate(i));
    }
  }
  
  public CircleManager(int N, int Rmin, int Rmax){
    this.N = N;
    this.Rmin = Rmin;
    this.Rmax = Rmax;
    this.init();
  }
  
  public void update(){
    for(int i = 0;i < N;i++){
        circles[i].update();
    }
  }
  
  public void draw(){
    for(int i = 0;i < N;i++){
        circles[i].draw();
    }
  }
  
  public void check(){
    for(int i = 0;i < N;i++){
        circles[i].checkEdge();
        for(int j = 0; j < i; j++){
            circles[i].checkOther(circles[j]);
        }
    }
  }
}

MyCircle 类已经实现了单个小球的各种功能,接下来需要管理所有的小球了。

2. 2. 2 随机生成小球

随机生成小球需要保证位置不冲突、主要包含两个方面。

一是不出界,二是不能与其它球冲突

// 随机生成小球,如果冲突, 返回 false,构造出该小球,并返回true
public boolean generate(int n){
    float x = random(width);
    float y = random(height);
    float r = random(Rmin, Rmax);
    
    if(x - r < 0 || x + r > width ||  y - r < 0 || y + r > height)
        return false;
      
    for(int i = 0; i < n; i++){
        if(dist(x, y, circles[i].x, circles[i].y) < r + circles[i].r)
             return false;
    }
    
    circles[n] = new MyCircle(x, y, r);
    return true;
  }
  
  // 依次生成每一个小球
  public void init(){
    circles = new MyCircle[this.N];
    
    for(int i = 0;i < N;i++){
        while(!generate(i));
    }
  }

主函数绘制

void setup() {
  background(255);
  size(680, 480);
  stroke(200);
  colorMode(HSB);
  
  manager = new CircleManager(N, Rmin, Rmax);
}


void draw() {
  background(255);
  manager.check();
  manager.update();
  manager.draw();
}

程序效果

你可能感兴趣的:(Processing,笔记)