天天看點

Processing-對象(class)

Processing 允許使用面向對象程式設計(OOP)技術來使 Processing 應用程式更易于開發和維護。與其他面向對象的語言一樣,Processing 使用 ​

​Class​

​ 的概念來定義對象模闆。

我們先來看一個例子:假設平坦的馬路上跑着一輛轎車,轎車的顔色為白色,目前速度為1公裡每小時,轎車類型為自動擋。現在我們想在Processing裡繪制這樣一個場景,如何做呢?

// 定義轎車的顔色
color c;
// 定義轎車的x坐标位置
float xpos;
// 定義轎車的y坐标位置
float ypos;
// 定義轎車的車速
float xspeed;
// 環境初始化。
// 此方法在軟體啟動時,被系統調用一次。
void setup() {
  // 初始化視窗大小
  size(200, 200);
  // 初始化轎車顔色
  c = color(255);
  // 初始化轎車的x坐标
  xpos = width/2;
  // 初始化轎車的y坐标
  ypos = height/2;
  // 初始化轎車的車速
  xspeed = 1;
}
// 畫圖。
// 此方法被系統預設循環調用。
void draw() {
  // 設定窗體背景色為黑色
  background(0);
  // 調用display()方法
  display();
  // 調用drive()方法
  drive();
}
// 自定義顯示轎車的方法
void display(){
  // 設定轎車的錨定點為矩形中心
  rectMode(CENTER);
  // 設定轎車的顔色
  fill(c);
  // 将轎車畫成矩形
  rect(xpos, ypos, 20, 10);
}
// 自定義轎車的制動方法
void drive(){
  // 轎車将在x軸上向前移動,
  // 移動的速度為xspeed
  xpos = xpos + xspeed;
  // 判斷轎車是否超出了窗體的右側,
  // 若超出,則轎車将從窗體左側重新駛入。
  if(xpos > width){
  // 将轎車的位置重新設定為窗體的左側
    xpos = 0;
  }
}      

上面的這段代碼,就是我們通常最先想到的方法。這種方式很顯然不太友好,為什麼這麼說呢?假設我們想要再建立一輛轎車,顔色為紅色,速度為2公裡每小時,那豈不是還要再定義一遍上面用到的變量?比如,車的顔色為了分别記錄兩輛車,是以要定義兩個​

​color​

​,位置記錄也要重新定義一遍,車速的變量也要重新定義一遍。以此類推,要是定義五輛轎車,那就要寫五遍同樣的變量。嗯,這确實是個問題。那應該怎麼辦呢?

嗯,這就涉及到今天所要講的内容,對象。

真實的世界裡,每個具體的事物都是對象,某一輛轎車,是一個對象,再一輛轎車,又是一個對象,多輛轎車,就是多個對象,以此類推。如果我們定義一個模具,通過這個模具可以馬上定制出,具有不同屬性的轎車,那不就友善了麼?到那個時候,我們想要多少轎車,就可以很容易的定制出多少轎車。那這個模具,在Processing這裡,稱之為​

​class​

​,也就是類。我們定義一個類,也就是定義了一個模具,以後想要多少轎車,就可以用這個模具定制出多少轎車。妙哉吧!好,讓我們看看這個類都包括哪些内容,具體怎麼定義?

一般來說,一個類包括四部分,分别為,類名,資料,構造器,方法。那麼,接下來讓我們講上面的示例改造成一個轎車的類,友善我們以後使用。

class Car{
  color c;
  float xpos;
  float ypos;
  float xspeed;

 Car(color tempC, float tempXpos, float tempYpos, float tempXspeed){
    c = tempC;
    xpos = tempXpos;
    ypos = tempYpos;
    xspeed = tempXspeed;
  }

  void display() {
    rectMode(CENTER);
    fill(c);
    rect(xpos, ypos, 20, 10);
  }

  void drive(){
    xpos = xpos + xspeed;
    if (xpos > width) {
        xpos = 0;
    }
  }
}      

上面代碼中,分别定義資料、定義構造器、定義方法。

1)構造器:

其命名要與類名保持一樣,然後會在定義對象的時候,自動調用。除此之外,構造器還可以進行初始化變量。定義一個新的對象,需要用到​

​new​

​關鍵字,緊接着就是類名,類名後面的括号,可以傳入構造器中,括号裡定義的參數。比如定義一個新的轎車對象,示例代碼如下:

myCar = new Car(color(255, 0, 0), 0, 100, 1);      

2)方法:

每個方法都有傳回數值,關鍵字​

​void​

​​比較特殊,它定義了此方法可以沒有傳回值,或者說,傳回值可以為空。緊接着,後面的​

​display()​

​​為方法名,括号裡可以放傳入的參數,此處為空。如果方法的傳回類型不是​

​void​

​​,則需要在方法的最後一行添加一條​

​return​

​​語句,​

​return​

​​後面有一個空格,然後是需要傳回的結果。由于此方法的傳回類型為​

​void​

​​,是以方法的最後一行的省掉了​

​return​

​語句。

好了,回到項目主體

// 聲明轎車變量myCar
Car myCar1;
Car myCar2;
// 環境初始化。
// 此方法在軟體啟動時,被系統調用一次。
void setup() {
  // 設定視窗
  size(200, 200);
  // 建立myCar對象。
  // 并傳入四個參數:
  // tempC = color(255, 0, 0)
  // tempXpos = 0
  // tempYpos = 100
  // tempXspeed = 1
  myCar1 = new Car(color(255, 0, 0), 0, 100, 1);
  // 參見上面myCar1的注釋
  myCar2 = new Car(color(0, 255, 0), 0, 150, 1.5);
}
// 畫圖
// 此方法被系統預設循環調用
void draw() {
  // 設定背景色為黑色
  background(0);
  // 調用myCar1對象的drive()方法
  myCar1.drive();
  // 調用myCar對象的display()方法
  myCar1.display();
  // 調用myCar2對象的drive()方法
  myCar2.drive();
  // 調用myCar2對象的display()方法
  myCar2.display();
}      

在上面的主體架構中,建立了兩個轎車對象,一個是​

​myCar1​

​​,另一個是​

​myCar2​

​​。在架構​

​setup​

​​中進行建立,并初始化相應參數。在架構​

​draw()​

​​方法中,對兩個對象的​

​drive()​

​​方法和​

​display()​

​​方法分别進行了調用。這裡要說的一點是,調用對象的方法需要在對象後面加一個​

​.​

​,然後緊跟方法名。

Processing-對象(class)

參考:​​http://ohcoder.com/blog/2016/03/18/processing-fun-object/​​

最後,我們舉一個水滴擴散的例子:

class Drop {
 
  int x, y;     // Coordinate (center of circle)
  int diameter;     // Diameter of circle (unused == 0).
   
  void init( int ix, int iy ) {
   x = ix;
   y = iy;
   diameter = 1;
  }
   
  void spread() {
    if (diameter > 0) diameter += 1;
  }
   
  void show() {
    if (diameter > 0) {
      ellipse( x, y, diameter, diameter );
      if (diameter > 500) diameter = 0;
    }
  }
   
}      

現在我們來看一下如何使用 ​

​Drop​

​​ 類來建構一些利用使用者輸入的圖形。清單 4 給出使用 ​

​Drop​

​​ 類的應用程式。第一步是建立一個水滴數組(稱為 ​

​drops​

​​)。之後進行幾個定義(​

​drops​

​​ 數組中的水滴數和工作索引)。在 ​

​setup​

​​ 函數中,您可以建立顯示視窗并初始化 ​

​drops​

​​ 數組(所有直徑為 0 或未使用)。​

​draw​

​​ 函數相當簡單,因為水滴的核心功能在類本身内部(​​清單 3​​​ 中的 ​

​spread​

​​ 和 ​

​show​

​​)最後,添加 UI 部分,該部分允許使用者定義水滴從何處開始。​

​mousePressed​

​ 回調函數通過目前滑鼠位置(目前有一個直徑且是使用過的)初始化水滴,然後遞增目前水滴索引。

Drop[] drops;
int numDrops = 30;
int curDrop = 0;
 
void setup() {
  size(400, 400);
  ellipseMode(CENTER);
  smooth();
  drops = new Drop[numDrops];
  for (int i = 0 ; i < numDrops ; i++) {
    drops[i] = new Drop();
    drops[i].diameter = 0;
  }
}
 
void draw() {
  background(0);
  for (int i = 0 ; i < numDrops ; i++) {
      drops[i].spread();
      drops[i].show();
  }
}
 
void mousePressed() {
  drops[curDrop].init( mouseX, mouseY );
  if (++curDrop == numDrops) curDrop = 0;
}      
Processing-對象(class)