如何将交互和动画添加到处理中绘制的形状?

发布于 2025-01-23 09:25:55 字数 836 浏览 2 评论 0 原文

我正在尝试编码装满形状(房屋)的画布,并在处理中对它们进行动画。

这是一个形状的示例:

void house(int x, int y) { 
  pushMatrix(); 
  translate(x, y); 
  fill(0, 200, 0); 
  triangle(15, 0, 0, 15, 30, 15); 
  rect(0, 15, 30, 30); 
  rect(12, 30, 10, 15); 
  popMatrix();
}

通过动画,我的意思是将它们移动到随机的方向上。

我还想添加基本的互动:当悬停在房屋上时,颜色会改变。

目前,我设法渲染了一个装满房屋的画布:

void setup() { 
  size(500, 500); 
  background(#74F5E9); 
  for (int i = 30; i < 500; i = i + 100) { 
    for (int j = 30; j < 500; j = j + 100) { 
      house(i, j);
    }
  }
} 
void house(int x, int y) { 
  pushMatrix(); 
  translate(x, y); 
  fill(0, 200, 0); 
  triangle(15, 0, 0, 15, 30, 15); 
  rect(0, 15, 30, 30); 
  rect(12, 30, 10, 15); 
  popMatrix();
}

I'm trying to code a canvas full of shapes(houses) and animate them in processing.

Here's an example of shape:

void house(int x, int y) { 
  pushMatrix(); 
  translate(x, y); 
  fill(0, 200, 0); 
  triangle(15, 0, 0, 15, 30, 15); 
  rect(0, 15, 30, 30); 
  rect(12, 30, 10, 15); 
  popMatrix();
}

By animation I mean moving them in random directions.

I would also like to add basic interaction: when hovering over a house it's colour would change.

At the moment I've managed to render a canvas full of houses:

void setup() { 
  size(500, 500); 
  background(#74F5E9); 
  for (int i = 30; i < 500; i = i + 100) { 
    for (int j = 30; j < 500; j = j + 100) { 
      house(i, j);
    }
  }
} 
void house(int x, int y) { 
  pushMatrix(); 
  translate(x, y); 
  fill(0, 200, 0); 
  triangle(15, 0, 0, 15, 30, 15); 
  rect(0, 15, 30, 30); 
  rect(12, 30, 10, 15); 
  popMatrix();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

因为看清所以看轻 2025-01-30 09:25:55

没有看到源代码:您尝试的草图很难说。

它们可以通过多种方式进行动画,目前尚不清楚您的意思。例如,是每个正方形的位置/旋转/刻度,是每个正方形的角落/顶点吗?

您的脑海中可能有一个清晰的想法,但是问题的当前形式是模棱两可的。我们也不知道您的舒适度具有各种概念,例如类/对象/pvector/pshape/etc。如果您要“故事板”这个动画,它会是什么样?将问题分解并以任何人都能理解的方式解释它实际上也可以帮助您自己找出解决方案。

处理有很多例子。根据我对您的问题的理解,我发现一些相关的内容。

您可以查看对象并创建形状示例:

  1. file&gt;示例&gt;基础&GT;对象&gt;对象:演示分组绘图/动画(宽松,阻尼)。您可以调整此示例绘制一个平方,并且一旦您对外观/运动感到满意,就可以使用数组或 arraylist
  2. file&gt;示例&gt;主题&gt;创建形状&gt; PolygonpShapeoop3 :使用 pShape 对对象进行动画对象。
  3. file&gt;示例&gt;主题&gt;创建形状&gt; wigglepshape :此示例演示了如何访问和修改 pShape

参考的顶点,我只需复制/粘贴上面提到的示例:

objects

/**
 * Objects
 * by hbarragan. 
 * 
 * Move the cursor across the image to change the speed and positions
 * of the geometry. The class MRect defines a group of lines.
 */

MRect r1, r2, r3, r4;
 
void setup()
{
  size(640, 360);
  fill(255, 204);
  noStroke();
  r1 = new MRect(1, 134.0, 0.532, 0.1*height, 10.0, 60.0);
  r2 = new MRect(2, 44.0, 0.166, 0.3*height, 5.0, 50.0);
  r3 = new MRect(2, 58.0, 0.332, 0.4*height, 10.0, 35.0);
  r4 = new MRect(1, 120.0, 0.0498, 0.9*height, 15.0, 60.0);
}
 
void draw()
{
  background(0);
  
  r1.display();
  r2.display();
  r3.display();
  r4.display();
 
  r1.move(mouseX-(width/2), mouseY+(height*0.1), 30);
  r2.move((mouseX+(width*0.05))%width, mouseY+(height*0.025), 20);
  r3.move(mouseX/4, mouseY-(height*0.025), 40);
  r4.move(mouseX-(width/2), (height-mouseY), 50);
}
 
class MRect 
{
  int w; // single bar width
  float xpos; // rect xposition
  float h; // rect height
  float ypos ; // rect yposition
  float d; // single bar distance
  float t; // number of bars
 
  MRect(int iw, float ixp, float ih, float iyp, float id, float it) {
    w = iw;
    xpos = ixp;
    h = ih;
    ypos = iyp;
    d = id;
    t = it;
  }
 
  void move (float posX, float posY, float damping) {
    float dif = ypos - posY;
    if (abs(dif) > 1) {
      ypos -= dif/damping;
    }
    dif = xpos - posX;
    if (abs(dif) > 1) {
      xpos -= dif/damping;
    }
  }
 
  void display() {
    for (int i=0; i<t; i++) {
      rect(xpos+(i*(d+w)), ypos, w, height*h);
    }
  }
}

polygonpshapeoop3

/**
 * PolygonPShapeOOP. 
 * 
 * Wrapping a PShape inside a custom class 
 * and demonstrating how we can have a multiple objects each
 * using the same PShape.
 */


// A list of objects
ArrayList<Polygon> polygons;

// Three possible shapes
PShape[] shapes = new PShape[3];

void setup() {
  size(640, 360, P2D);
  
  shapes[0] = createShape(ELLIPSE,0,0,100,100);
  shapes[0].setFill(color(255, 127));
  shapes[0].setStroke(false);
  shapes[1] = createShape(RECT,0,0,100,100);
  shapes[1].setFill(color(255, 127));
  shapes[1].setStroke(false);
  shapes[2] = createShape();  
  shapes[2].beginShape();
  shapes[2].fill(0, 127);
  shapes[2].noStroke();
  shapes[2].vertex(0, -50);
  shapes[2].vertex(14, -20);
  shapes[2].vertex(47, -15);
  shapes[2].vertex(23, 7);
  shapes[2].vertex(29, 40);
  shapes[2].vertex(0, 25);
  shapes[2].vertex(-29, 40);
  shapes[2].vertex(-23, 7);
  shapes[2].vertex(-47, -15);
  shapes[2].vertex(-14, -20);
  shapes[2].endShape(CLOSE);

  // Make an ArrayList
  polygons = new ArrayList<Polygon>();
  
  for (int i = 0; i < 25; i++) {
    int selection = int(random(shapes.length));        // Pick a random index
    Polygon p = new Polygon(shapes[selection]);        // Use corresponding PShape to create Polygon
    polygons.add(p);
  }
}

void draw() {
  background(102);

  // Display and move them all
  for (Polygon poly : polygons) {
    poly.display();
    poly.move();
  }
}

// A class to describe a Polygon (with a PShape)

class Polygon {
  // The PShape object
  PShape s;
  // The location where we will draw the shape
  float x, y;
  // Variable for simple motion
  float speed;

  Polygon(PShape s_) {
    x = random(width);
    y = random(-500, -100); 
    s = s_;
    speed = random(2, 6);
  }
  
  // Simple motion
  void move() {
    y+=speed;
    if (y > height+100) {
      y = -100;
    }
  }
  
  // Draw the object
  void display() {
    pushMatrix();
    translate(x, y);
    shape(s);
    popMatrix();
  }
}

wigglepshape:

/**
 * WigglePShape. 
 * 
 * How to move the individual vertices of a PShape
 */


// A "Wiggler" object
Wiggler w;

void setup() {
  size(640, 360, P2D);
  w = new Wiggler();
}

void draw() {
  background(255);
  w.display();
  w.wiggle();
}

// An object that wraps the PShape

class Wiggler {
  
  // The PShape to be "wiggled"
  PShape s;
  // Its location
  float x, y;
  
  // For 2D Perlin noise
  float yoff = 0;
  
  // We are using an ArrayList to keep a duplicate copy
  // of vertices original locations.
  ArrayList<PVector> original;

  Wiggler() {
    x = width/2;
    y = height/2; 

    // The "original" locations of the vertices make up a circle
    original = new ArrayList<PVector>();
    for (float a = 0; a < radians(370); a += 0.2) {
      PVector v = PVector.fromAngle(a);
      v.mult(100);
      original.add(new PVector());
      original.add(v);
    }
    
    // Now make the PShape with those vertices
    s = createShape();
    s.beginShape(TRIANGLE_STRIP);
    s.fill(80, 139, 255);
    s.noStroke();
    for (PVector v : original) {
      s.vertex(v.x, v.y);
    }
    s.endShape(CLOSE);
  }

  void wiggle() {
    float xoff = 0;
    // Apply an offset to each vertex
    for (int i = 1; i < s.getVertexCount(); i++) {
      // Calculate a new vertex location based on noise around "original" location
      PVector pos = original.get(i);
      float a = TWO_PI*noise(xoff,yoff);
      PVector r = PVector.fromAngle(a);
      r.mult(4);
      r.add(pos);
      // Set the location of each vertex to the new one
      s.setVertex(i, r.x, r.y);
      // increment perlin noise x value
      xoff+= 0.5;
    }
    // Increment perlin noise y value
    yoff += 0.02;
  }

  void display() {
    pushMatrix();
    translate(x, y);
    shape(s);
    popMatrix();
  }
}

update

基于您的评论,这是修改了草图的版本,因此盘旋房屋的颜色更改:

// store house bounding box dimensions for mouse hover check
int houseWidth  = 30;
// 30 px rect height + 15 px triangle height
int houseHeight = 45;

void setup() { 
  size(500, 500); 
}

void draw(){
  background(#74F5E9); 
  for (int i = 30; i < 500; i = i + 100) { 
    for (int j = 30; j < 500; j = j + 100) {
      // check if the cursor is (roughly) over a house
      // and render with a different color
      if(overHouse(i, j)){
        house(i, j, color(0, 0, 200));
      }else{
        house(i, j, color(0, 200, 0));
      }
    }
  }
}

void house(int x, int y, color fillColor) { 
  pushMatrix(); 
  translate(x, y); 
  fill(fillColor); 
  triangle(15, 0, 0, 15, 30, 15); 
  rect(0, 15, 30, 30); 
  rect(12, 30, 10, 15); 
  popMatrix();
}

// from Processing RollOver example
// https://processing.org/examples/rollover.html
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;
  }
}

// check if the mouse is within the bounding box of a house
boolean overHouse(int x, int y){
  // offset half the house width since the pivot is at the tip of the house 
  // the horizontal center
  return overRect(x - (houseWidth / 2), y, houseWidth, houseHeight);
}

代码为已评论,但这是主要的要点:

  • house()函数已更改,因此您可以指定颜色
  • Overcret()函数已从翻转示例
  • 复制 Overhouse()函数使用 OVERTRECT(),但添加了水平偏移以考虑到房屋是从中间点绘制的(房屋提示是形状的枢轴点)

关于动画,处理具有示例

”处理示例:Motion

让我们开始以正弦运动为例。
sin() 函数呈一个角度(默认情况下,在Radians中)并返回-1.0至1.0之间的值,

因为您已经在2D网格中计算每个房屋的位置,因此您可以使用 sin()来抵消每个位置以使其动画。关于它的好处是周期性:无论您提供哪个角度,您始终获得-1.0和1.0之间的值。这将为您节省需要将每个房屋的当前X,Y位置存储在阵列中,以便您可以将它们递增为不同的方向。

这是上述草图的修改版本,该版本使用 sin()进行动画:

// store house bounding box dimensions for mouse hover check
int houseWidth  = 30;
// 30 px rect height + 15 px triangle height
int houseHeight = 45;

void setup() { 
  size(500, 500); 
}

void draw(){
  background(#74F5E9); 
  for (int i = 30; i < 500; i = i + 100) { 
    for (int j = 30; j < 500; j = j + 100) {
      
      // how fast should each module move around a circle (angle increment)
      // try changing i with j, adding i + j or trying other mathematical expressions
      // also try changing 0.05 to other values
      float phase = (i + frameCount) * 0.05;
      // try changing amplitude to other values
      float amplitude = 30.0;
      // map the sin() result from it's range to a pixel range (-30px to 30px for example)
      float xOffset = map(sin(phase), -1.0, 1.0, -amplitude, amplitude);
      // offset each original grid horizontal position (i) by the mapped sin() result
      float x = i + xOffset;
      // check if the cursor is (roughly) over a house
      // and render with a different color
      if(overHouse(i, j)){
        house(x, j, color(0, 0, 200));
      }else{
        house(x, j, color(0, 200, 0));
      }
    }
  }
}

void house(float x, float y, color fillColor) { 
  pushMatrix(); 
  translate(x, y); 
  fill(fillColor); 
  triangle(15, 0, 0, 15, 30, 15); 
  rect(0, 15, 30, 30); 
  rect(12, 30, 10, 15); 
  popMatrix();
}

// from Processing RollOver example
// https://processing.org/examples/rollover.html
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;
  }
}

// check if the mouse is within the bounding box of a house
boolean overHouse(int x, int y){
  // offset half the house width since the pivot is at the tip of the house 
  // the horizontal center
  return overRect(x - (houseWidth / 2), y, houseWidth, houseHeight);
}

仔细阅读评论并尝试调整代码以更好地了解其工作原理,并获得不同的动画的乐趣。

主要更改是:

  • 修改 house()函数使用float x,y位置(而不是int):这是为了避免转换 float int int < /code>使用 sin() map()并获取更平滑的动作(而不是运动将“捕捉”到整个像素的运动)
  • 映射到可以使用的位置为了将

计算X偏移量计算为可重复使用的功能的3个指令包装动画,您可以进行进一步的实验。如果您使用了类似技术,则每个房屋的Y位置怎么办? x和y呢?

逐步浏览代码。尝试理解它,更改它,打破它,修复并制作新的草图重复使用代码。

Without seeing source code: your attempted sketch it's very hard to tell.

They can be animated in many ways and it's unclear what you mean. For example, is that the position/rotation/scale of each square, is it the corners/vertices of each square, both ?

You might have a clear idea in your mind, but the current form of the question is ambiguous. We also don't know you're comfort level with various notions such as classes/objects/PVector/PShape/etc. If you were to 'story board' this animation what would it look like ? Breaking the problem down and explaining it in a way that anyone can understand might actually help you figure out a solution on your own as well.

Processing has plenty of examples. Here are a few I find relevant based on what my understanding is of your problem.

You can have a look at the Objects and Create Shapes examples:

  1. File > Examples > Basics > Objects > Objects: Demonstrates grouping drawing/animation (easing, damping). You can tweak this example draw a single square and once you're happy with the look/motion you can animate multiple using an array or ArrayList
  2. File > Examples > Topics > Create Shapes > PolygonPShapeOOP3: Great example using PShape to animate objects.
  3. File > Examples > Topics > Create Shapes > WigglePShape: This example demonstrates how to access and modify the vertices of a PShape

For reference I'm simply copy/pasting the examples mentioned above here as well:

Objects

/**
 * Objects
 * by hbarragan. 
 * 
 * Move the cursor across the image to change the speed and positions
 * of the geometry. The class MRect defines a group of lines.
 */

MRect r1, r2, r3, r4;
 
void setup()
{
  size(640, 360);
  fill(255, 204);
  noStroke();
  r1 = new MRect(1, 134.0, 0.532, 0.1*height, 10.0, 60.0);
  r2 = new MRect(2, 44.0, 0.166, 0.3*height, 5.0, 50.0);
  r3 = new MRect(2, 58.0, 0.332, 0.4*height, 10.0, 35.0);
  r4 = new MRect(1, 120.0, 0.0498, 0.9*height, 15.0, 60.0);
}
 
void draw()
{
  background(0);
  
  r1.display();
  r2.display();
  r3.display();
  r4.display();
 
  r1.move(mouseX-(width/2), mouseY+(height*0.1), 30);
  r2.move((mouseX+(width*0.05))%width, mouseY+(height*0.025), 20);
  r3.move(mouseX/4, mouseY-(height*0.025), 40);
  r4.move(mouseX-(width/2), (height-mouseY), 50);
}
 
class MRect 
{
  int w; // single bar width
  float xpos; // rect xposition
  float h; // rect height
  float ypos ; // rect yposition
  float d; // single bar distance
  float t; // number of bars
 
  MRect(int iw, float ixp, float ih, float iyp, float id, float it) {
    w = iw;
    xpos = ixp;
    h = ih;
    ypos = iyp;
    d = id;
    t = it;
  }
 
  void move (float posX, float posY, float damping) {
    float dif = ypos - posY;
    if (abs(dif) > 1) {
      ypos -= dif/damping;
    }
    dif = xpos - posX;
    if (abs(dif) > 1) {
      xpos -= dif/damping;
    }
  }
 
  void display() {
    for (int i=0; i<t; i++) {
      rect(xpos+(i*(d+w)), ypos, w, height*h);
    }
  }
}

PolygonPShapeOOP3:

/**
 * PolygonPShapeOOP. 
 * 
 * Wrapping a PShape inside a custom class 
 * and demonstrating how we can have a multiple objects each
 * using the same PShape.
 */


// A list of objects
ArrayList<Polygon> polygons;

// Three possible shapes
PShape[] shapes = new PShape[3];

void setup() {
  size(640, 360, P2D);
  
  shapes[0] = createShape(ELLIPSE,0,0,100,100);
  shapes[0].setFill(color(255, 127));
  shapes[0].setStroke(false);
  shapes[1] = createShape(RECT,0,0,100,100);
  shapes[1].setFill(color(255, 127));
  shapes[1].setStroke(false);
  shapes[2] = createShape();  
  shapes[2].beginShape();
  shapes[2].fill(0, 127);
  shapes[2].noStroke();
  shapes[2].vertex(0, -50);
  shapes[2].vertex(14, -20);
  shapes[2].vertex(47, -15);
  shapes[2].vertex(23, 7);
  shapes[2].vertex(29, 40);
  shapes[2].vertex(0, 25);
  shapes[2].vertex(-29, 40);
  shapes[2].vertex(-23, 7);
  shapes[2].vertex(-47, -15);
  shapes[2].vertex(-14, -20);
  shapes[2].endShape(CLOSE);

  // Make an ArrayList
  polygons = new ArrayList<Polygon>();
  
  for (int i = 0; i < 25; i++) {
    int selection = int(random(shapes.length));        // Pick a random index
    Polygon p = new Polygon(shapes[selection]);        // Use corresponding PShape to create Polygon
    polygons.add(p);
  }
}

void draw() {
  background(102);

  // Display and move them all
  for (Polygon poly : polygons) {
    poly.display();
    poly.move();
  }
}

// A class to describe a Polygon (with a PShape)

class Polygon {
  // The PShape object
  PShape s;
  // The location where we will draw the shape
  float x, y;
  // Variable for simple motion
  float speed;

  Polygon(PShape s_) {
    x = random(width);
    y = random(-500, -100); 
    s = s_;
    speed = random(2, 6);
  }
  
  // Simple motion
  void move() {
    y+=speed;
    if (y > height+100) {
      y = -100;
    }
  }
  
  // Draw the object
  void display() {
    pushMatrix();
    translate(x, y);
    shape(s);
    popMatrix();
  }
}

WigglePShape:

/**
 * WigglePShape. 
 * 
 * How to move the individual vertices of a PShape
 */


// A "Wiggler" object
Wiggler w;

void setup() {
  size(640, 360, P2D);
  w = new Wiggler();
}

void draw() {
  background(255);
  w.display();
  w.wiggle();
}

// An object that wraps the PShape

class Wiggler {
  
  // The PShape to be "wiggled"
  PShape s;
  // Its location
  float x, y;
  
  // For 2D Perlin noise
  float yoff = 0;
  
  // We are using an ArrayList to keep a duplicate copy
  // of vertices original locations.
  ArrayList<PVector> original;

  Wiggler() {
    x = width/2;
    y = height/2; 

    // The "original" locations of the vertices make up a circle
    original = new ArrayList<PVector>();
    for (float a = 0; a < radians(370); a += 0.2) {
      PVector v = PVector.fromAngle(a);
      v.mult(100);
      original.add(new PVector());
      original.add(v);
    }
    
    // Now make the PShape with those vertices
    s = createShape();
    s.beginShape(TRIANGLE_STRIP);
    s.fill(80, 139, 255);
    s.noStroke();
    for (PVector v : original) {
      s.vertex(v.x, v.y);
    }
    s.endShape(CLOSE);
  }

  void wiggle() {
    float xoff = 0;
    // Apply an offset to each vertex
    for (int i = 1; i < s.getVertexCount(); i++) {
      // Calculate a new vertex location based on noise around "original" location
      PVector pos = original.get(i);
      float a = TWO_PI*noise(xoff,yoff);
      PVector r = PVector.fromAngle(a);
      r.mult(4);
      r.add(pos);
      // Set the location of each vertex to the new one
      s.setVertex(i, r.x, r.y);
      // increment perlin noise x value
      xoff+= 0.5;
    }
    // Increment perlin noise y value
    yoff += 0.02;
  }

  void display() {
    pushMatrix();
    translate(x, y);
    shape(s);
    popMatrix();
  }
}

Update

Based on your comments here's an version of your sketch modified so the color of the hovered house changes:

// store house bounding box dimensions for mouse hover check
int houseWidth  = 30;
// 30 px rect height + 15 px triangle height
int houseHeight = 45;

void setup() { 
  size(500, 500); 
}

void draw(){
  background(#74F5E9); 
  for (int i = 30; i < 500; i = i + 100) { 
    for (int j = 30; j < 500; j = j + 100) {
      // check if the cursor is (roughly) over a house
      // and render with a different color
      if(overHouse(i, j)){
        house(i, j, color(0, 0, 200));
      }else{
        house(i, j, color(0, 200, 0));
      }
    }
  }
}

void house(int x, int y, color fillColor) { 
  pushMatrix(); 
  translate(x, y); 
  fill(fillColor); 
  triangle(15, 0, 0, 15, 30, 15); 
  rect(0, 15, 30, 30); 
  rect(12, 30, 10, 15); 
  popMatrix();
}

// from Processing RollOver example
// https://processing.org/examples/rollover.html
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;
  }
}

// check if the mouse is within the bounding box of a house
boolean overHouse(int x, int y){
  // offset half the house width since the pivot is at the tip of the house 
  // the horizontal center
  return overRect(x - (houseWidth / 2), y, houseWidth, houseHeight);
}

The code is commented, but here are the main takeaways:

  • the house() function has been changed so you can specify a color
  • the overRect() function has been copied from the Rollover example
  • the overHouse() function uses overRect(), but adds a horizontal offset to take into account the house is drawn from the middle top point (the house tip is the shape's pivot point)

Regarding animation, Processing has tons of examples:

Processing examples: Motion / Simulate / Vectors screenshot of the bottom of the page which includes thumbnails

Let's start take sine motion as an example.
The sin() function takes an angle (in radians by default) and returns a value between -1.0 and 1.0

Since you're already calculating positions for each house within a 2D grid, you can offset each position using sin() to animate it. The nice thing about it is cyclical: no matter what angle you provide you always get values between -1.0 and 1.0. This would save you the trouble of needing to store the current x, y positions of each house in arrays so you can increment them in a different directions.

Here's a modified version of the above sketch that uses sin() to animate:

// store house bounding box dimensions for mouse hover check
int houseWidth  = 30;
// 30 px rect height + 15 px triangle height
int houseHeight = 45;

void setup() { 
  size(500, 500); 
}

void draw(){
  background(#74F5E9); 
  for (int i = 30; i < 500; i = i + 100) { 
    for (int j = 30; j < 500; j = j + 100) {
      
      // how fast should each module move around a circle (angle increment)
      // try changing i with j, adding i + j or trying other mathematical expressions
      // also try changing 0.05 to other values
      float phase = (i + frameCount) * 0.05;
      // try changing amplitude to other values
      float amplitude = 30.0;
      // map the sin() result from it's range to a pixel range (-30px to 30px for example)
      float xOffset = map(sin(phase), -1.0, 1.0, -amplitude, amplitude);
      // offset each original grid horizontal position (i) by the mapped sin() result
      float x = i + xOffset;
      // check if the cursor is (roughly) over a house
      // and render with a different color
      if(overHouse(i, j)){
        house(x, j, color(0, 0, 200));
      }else{
        house(x, j, color(0, 200, 0));
      }
    }
  }
}

void house(float x, float y, color fillColor) { 
  pushMatrix(); 
  translate(x, y); 
  fill(fillColor); 
  triangle(15, 0, 0, 15, 30, 15); 
  rect(0, 15, 30, 30); 
  rect(12, 30, 10, 15); 
  popMatrix();
}

// from Processing RollOver example
// https://processing.org/examples/rollover.html
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;
  }
}

// check if the mouse is within the bounding box of a house
boolean overHouse(int x, int y){
  // offset half the house width since the pivot is at the tip of the house 
  // the horizontal center
  return overRect(x - (houseWidth / 2), y, houseWidth, houseHeight);
}

Read through the comments and try to tweak the code to get a better understanding of how it works and have fun coming up with different animations.

The main changes are:

  • modifying the house() function to use float x,y positions (instead of int): this is to avoid converting float to int when using sin(), map() and get smoother motions (instead of motion that "snaps" to whole pixels)
  • Mapped sine to positions which can be used to animate

Wrapping the 3 instructions that calculate the x offset into a reusable function would allow you do further experiment. What if you used a similar technique the y position of each house ? What about both x and y ?

Go through the code step by step. Try to understand it, change it, break it, fix it and make new sketches reusing code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文