使用 pushmatrix() 函数显示消息的可点击 3d 形状?

Clickable 3d shape using pushmatrix() function to show a message?

你好,我想知道如何让我的 3D 条在每次点击时显示一条消息。

例如,我在 2D 图像上有一个 3D 条,当我将鼠标悬停在它上面并单击它时,它应该会在同一屏幕上显示消息,如果我再次单击它,它应该会使消息消失.

我的代码:

boolean drawText = false;

void setup() {
size(800, 600, P3D);
}

void draw() {
background(0);
noStroke();

pushMatrix();
fill(204, 0, 0, 151);
translate(42, 75, 0);
box (5, 5, 10);
if(dist(mouseX,mouseY,27,-22)<0){
cursor(HAND);
} else {
cursor(ARROW);
}
if (drawText) {
fill(#FFFF00);
text("Hi!", 27, -22);
}
popMatrix(); 

pushMatrix();
fill(204, 0, 0, 151);
translate(42, 75, 0);
box (5, 5, 10);
popMatrix(); 

}
void mousePressed() {
if (mouseButton == LEFT && dist(mouseX,mouseY,27,-22)<0) {
drawText = drawText ? false : true;
}
}

我想知道如果我有多个 3D 形状,我如何使用 mousePressed() 创建一个按钮以允许我在单击形状时使用左键单击。另外,由于我使用 pushMatrix() 函数,它仍然可以工作吗?

首先,我建议缩进您的代码(Windows/Linux 上的 Ctrl + T、OSX 上的 CMD+T 会为您完成这项工作)。这使您的代码更易于阅读/快速扫描。

在漫长的 运行 中,您会发现花在 reading/debugging 代码上的时间比实际打字还多,所以我强烈建议您做任何让您的生活更轻松的事情:)

根据我在您的代码中收集到的信息,您似乎对坐标和坐标系感到困惑。请查看 Coordinate Systems and 2D Transformation 教程

我这么说是因为您在坐标 42, 75 处将两个框绘制在彼此之上。 此外,您正在检查鼠标坐标和 27,-22 之间的距离(您还在那里绘制文本。顺便说一下,距离永远不会是 < 0

要调试您的程序,最好将其分解成多个部分并一次测试一件事。就我个人而言,在将假设实施到更大的程序之前,我会编写最小的草图来测试假设。

例如,用最少的测试草图就可以很容易地反驳 dist() < 0。 制作一个新草图,粘贴以下内容和 运行:

void draw(){
  background(255);
  line(50,50,mouseX,mouseY);
  fill(0);
  text("x:"+mouseX+",y:"+mouseY + "\nd:" + dist(mouseX,mouseY,50,50),mouseX,mouseY);
}

要记住的另一件事是,在检查框周围的 2D 屏幕边界时,您将使用全局坐标,而不是相对坐标(使用 translate() 进行偏移)。

这是您使用 dist():

修改后的草图版本
boolean drawText = false;

float radius = 22.5;
float diameter = radius * 2;

void setup() {
  size(800, 600, P3D);
}

void draw() {
  background(0);
  noStroke();

  pushMatrix();
  // visualise radius
  fill(255,30);

  ellipse(44, 80, diameter, diameter);
  ellipse(108, 80, diameter, diameter);

  fill(204, 0, 0, 151);
  translate(42, 75, 0);
  box (50, 50, 10);

  if(isOver(mouseX, mouseY, 44, 80, radius) ||
     isOver(mouseX, mouseY, 108, 80, radius)) {
    cursor(HAND);
  } else {
    cursor(ARROW);
  }
  if (drawText) {
    fill(#FFFF00);
    text("Hi!", 27, -22);
  }
  popMatrix(); 

  pushMatrix();
  fill(35, 198, 13, 151);
  translate(110, 75, 0);
  box (50, 50, 10);
  popMatrix();
}

void mousePressed() {
  if (mouseButton == LEFT) {

    if(isOver(mouseX, mouseY, 44, 80, radius) ||
       isOver(mouseX, mouseY, 108, 80, radius)) {

      drawText = !drawText;

     }
  }
}

boolean isOver(int mx, int my, float x, float y, float radius){
  return dist(mx,my,x,y) < radius;
}

切记我使用了几个快捷方式:

  • drawText = drawText ? false : true; 与使用 logical NOT)
  • drawText = !drawText; 相同
  • isOver() 函数类似于按钮示例 overCircle() 函数,但是它只是 return 一个布尔值(使用 < 作为条件运算符)

另请注意在用作按钮活动区域的方框附近绘制的圆圈,以及光标如何在方框角周围不发生变化。可以调整半径使其覆盖更多的框,但是由于椭圆的形状,活动区域将错过角落或越过侧面。另一个考虑是,如果您有许多框按钮,例如 dist() 可能会变慢(因为它在幕后使用 sqrt())。

我特别推荐 Button 示例中的 overRect() 函数:矩形将更好地适应该方向的 3D 框形状并且计算速度更快:

boolean drawText = false;

void setup() {
  size(800, 600, P3D);
}

void draw() {
  background(0);
  noStroke();

  pushMatrix();
  fill(204, 0, 0, 151);
  translate(42, 75, 0);
  box (50, 50, 10);

  if(isOver(mouseX, mouseY, 13, 47, 57, 57) ||
     isOver(mouseX, mouseY, 82, 47, 57, 57)) {
    cursor(HAND);
  } else {
    cursor(ARROW);
  }
  if (drawText) {
    fill(#FFFF00);
    text("Hi!", 24, -38);
  }
  popMatrix(); 

  pushMatrix();
  fill(35, 198, 13, 151);
  translate(110, 75, 0);
  box (50, 50, 10);
  popMatrix();
}

void mousePressed() {
  if (mouseButton == LEFT) {
    if(isOver(mouseX, mouseY, 13, 47, 57, 57) ||
       isOver(mouseX, mouseY, 82, 47, 57, 57)) {

      drawText = !drawText;

     }
  }
}

boolean isOver(int mx, int my, int x, int y, int w, int h){
  return ((mx >= x && mx <= x + w) &&
          (my >= y && my <= y + h));
}

作为一项改进,您可以在草图顶部为每个按钮的全局 2D 边界框 x、y、宽度和高度创建变量,以便轻松重复使用,而不是使用 copy/pasted 常量值。优点是它会使代码更灵活:更容易更改按钮位置、大小等。

如果您对函数和 return 值感到困惑,我推荐 Daniel Shiffman 的函数教程:

  1. 7.2: Functions Basics - Processing Tutorial
  2. 7.3: Modularity with Functions - Processing Tutorial
  3. 7.4: Reusability with Functions - Processing Tutorial