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)。
简而言之:
- 您可以将转换存储在矩阵中
- 您可以使用乘法将这些变换应用于向量
回到你的问题,检查一个点是否在一个应用了转换的盒子内,你可以这样做:
通过以下方式将测试点的坐标系转换为盒子的变换坐标系:
- 反转盒子的变换矩阵和
- 将该点与逆变换矩阵相乘。
这可能一开始很难理解,但一种看待的方式是想象你旋转整个“世界”(坐标系),所以你旋转的盒子是直的(基本上是在相反的方向旋转,或反转变换)然后检查该点是否在框中。
幸运的是,所有这些矩阵运算都不需要从头开始实现: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();
}
}