【问题标题】:Advanced rectangles collision in processing处理中的高级矩形碰撞
【发布时间】:2015-09-25 21:15:32
【问题描述】:

在处理中编码 (processing.org): 我想知道鼠标或其他形状何时与矩形碰撞, 这很容易,但我有一个问题:我希望它在矩形旋转时工作(例如:rotate(radians(90)))。

【问题讨论】:

标签: math processing


【解决方案1】:

Kevin 和 Asad 的贡献都很有用。

在使用 2D 渲染器方面,您需要为此推出自己的功能。为此,您应该熟悉一些线性代数(主要是向量和矩阵,无论如何也只是一些运算)。

我假设您已经熟悉 2D 转换(使用 pushMatrix()/popMatrix()translate(),rotate(),scale())如果没有,我强烈推荐 2D Transformations Processing tutorial

我将仅简要解释一些概念(因为它本身就是一个大话题)。

如果您之前使用过translate()/rotate()/scale(),那么这一切都是在幕后为您处理的矩阵运算。在 2D 中,转换可以存储在 3x3 矩阵中,如下所示:

X Y T
1 0 0
0 1 0
0 0 1

旋转和缩放存储在第 1 列和第 2 列(每列 2 个值),而平移存储在最后一列。从理论上讲,您可以使用 2x3 矩阵而不是 3x3 矩阵,但 NxN 矩阵具有一些不错的属性。其中一件好事是很容易与向量相乘。位置可以存储为向量,我们希望通过将向量与变换矩阵相乘来变换向量。如果将向量视为单列向量,则矩阵的 3x3 形式允许乘法(参见 matrix multiplication rules here)。

简而言之:

  1. 您可以将转换存储在矩阵中
  2. 您可以使用乘法将这些变换应用于向量

回到你的问题,检查一个点是否在一个应用了转换的盒子内,你可以这样做:

通过以下方式将测试点的坐标系转换为盒子的变换坐标系:

  1. 反转盒子的变换矩阵和
  2. 将该点与逆变换矩阵相乘。

这可能一开始很难理解,但一种看待的方式是想象你旋转整个“世界”(坐标系),所以你旋转的盒子是直的(基本上是在相反的方向旋转,或反转变换)然后检查该点是否在框中。

幸运的是,所有这些矩阵运算都不需要从头开始实现:PMatrix2D 可以解决这个问题。

这是一个基本的注释草图,解释了上述所有内容:

Box box1,box2;

void setup(){
  size(400,400);

  box1 = new Box(200,100);
  box1.translate(75,100);
  box1.rotate(radians(30));
  box1.scale(1.1);

  box2 = new Box(100,200);
  box2.translate(275,150);
  box2.rotate(radians(-5));
  box2.scale(.95);
}

void draw(){
  background(255);
  box1.update(mouseX,mouseY);
  box2.update(mouseX,mouseY);
  box1.draw();
  box2.draw();
}

class Box{

  PMatrix2D coordinates = new PMatrix2D();//box coordinate system
  PMatrix2D reverseCoordinates = new PMatrix2D();//inverted coordinate system

  PVector reversedTestPoint = new PVector();//allocate reversed point as vector
  PVector testPoint = new PVector();//allocate regular point as vector


  float w,h;//box width and height
  boolean isHovered;

  Box(float w,float h){
    this.w = w;
    this.h = h;
  }
  //whenever we update the regular coordinate system, we update the reversed one too
  void updateReverseCoordinates(){
    reverseCoordinates = coordinates.get();//clone the original coordinate system
    reverseCoordinates.invert();//simply invert it
  }

  void translate(float x,float y){
    coordinates.translate(x,y);  
    updateReverseCoordinates();
  }
  void rotate(float angle){
    coordinates.rotate(angle);  
    updateReverseCoordinates();
  }
  void scale(float s){
    coordinates.scale(s);
    updateReverseCoordinates();
  }
  boolean isOver(float x,float y){
    reversedTestPoint.set(0,0);//reset the reverse test point
    testPoint.set(x,y);//set the x,y coordinates we want to test
    //transform the passed x,y coordinates to the reversed coordinates using matrix multiplication
    reverseCoordinates.mult(testPoint,reversedTestPoint);
    //simply test the bounding box
    return ((reversedTestPoint.x >= 0 && reversedTestPoint.x <= w) && 
            (reversedTestPoint.y >= 0 && reversedTestPoint.y <= h));
  }

  void update(float x,float y){
    isHovered = isOver(x,y);
  }
  void draw(){
    if(isHovered) fill(127);
    else          fill(255);
    pushMatrix();
    applyMatrix(coordinates);
    rect(0,0,w,h);
    popMatrix();
  }

}

【讨论】:

    【解决方案2】:

    您正在寻找modelX()modelY() 函数。只需传入mouseXmouseY(z 为0)即可找到鼠标在旋转空间中的位置。同样,传入矩形的位置以找到它们的旋转点。

    这是参考中的示例:

    void setup() {
      size(500, 500, P3D);
      noFill();
    }
    
    void draw() {
      background(0);
    
      pushMatrix();
      // start at the middle of the screen
      translate(width/2, height/2, -200);     
      // some random rotation to make things interesting
      rotateY(1.0); //yrot);
      rotateZ(2.0); //zrot);
      // rotate in X a little more each frame
      rotateX(frameCount / 100.0);
      // offset from center
      translate(0, 150, 0);
    
      // draw a white box outline at (0, 0, 0)
      stroke(255);
      box(50);
    
      // the box was drawn at (0, 0, 0), store that location
      float x = modelX(0, 0, 0);
      float y = modelY(0, 0, 0);
      float z = modelZ(0, 0, 0);
      // clear out all the transformations
      popMatrix();
    
      // draw another box at the same (x, y, z) coordinate as the other
      pushMatrix();
      translate(x, y, z);
      stroke(255, 0, 0);
      box(50);
      popMatrix();
    }
    

    【讨论】:

    • 谢谢,但是有什么办法可以在 2D/默认渲染器中使用它
    • @Yaron 是的。此代码只是一个示例。当你尝试使用默认渲染器时发生了什么?
    猜你喜欢
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多