[英]Circle collision optimization in processing
我創建了一個項目,我在其中操縱球。 我有一些問題,我不知道如何解決。 我正在使用處理。
在我的項目中,圓圈相互碰撞。 此時,為了檢查對象是否相互碰撞,我 go 遍歷了所有對象,這是非常欠優化的。 我想通過創建一個 NetForCircum class 來改進這一點,我在其中放置對象以僅比較那些靠近的對象。 我的主要問題是,如果圓的中心位於網格的不同部分,則無法將對象插入網格。 另外,如果 window 大小發生變化,我不知道如何更改網格大小。
void checkForCollision()
{
for (int i = 0; i<cir.size() -1; i++)
{
for (int j = i + 1; j<cir.size(); j++)
{
//calculating distance between object
PVector lengthFrom_i_to_j= PVector.sub( cir.get(j).point, cir.get(i).point);
float oldDist = lengthFrom_i_to_j.mag();
float min_dyst = cir.get(j).radius + cir.get(i).radius;
//checking for collision
if (oldDist <= min_dyst)
{
collision(cir.get(i), cir.get(j), oldDist, min_dyst, lengthFrom_i_to_j);
}
}
}
}
void collision(Circum con1, Circum con2, float dist_, float min_, PVector lock)
{
float u1, u2, distance = dist_, min_dyst = min_;
//static collision
float distanceCorrection = (min_dyst-distance)/2.0;
PVector correctionVector = lock.normalize().mult(distanceCorrection);
con2.point.add(correctionVector);
con1.point.sub(correctionVector);
//dynamic collision
// Defining the X axis
PVector dirX = lock.copy();
dirX.normalize();
// Defining the Y axis
PVector dirY = new PVector(dirX.y, -dirX.x);
// X coordinates of velocities
float vx1 = dirX.dot(con1.velocity);
float vx2 = dirX.dot(con2.velocity);
// Y coordinates of velocities
float vy1 = dirY.dot(con1.velocity);
float vy2 = dirY.dot(con2.velocity);
// Applying the collision to X coordinates
u1 = (2 * vx2 * con2.mass + vx1 * (con1.mass - con2.mass)) / (con1.mass + con2.mass);
u2 = (2 * vx1 * con1.mass + vx2 * (con2.mass - con1.mass)) / (con1.mass + con2.mass);
// Turning velocities back into vectors
PVector vel1 = PVector.mult(dirX, u1);
PVector vel2 = PVector.mult(dirX, u2);
vel1.add(PVector.mult(dirY, vy1));
vel2.add(PVector.mult(dirY, vy2));
con1.velocity = vel1;
con2.velocity = vel2;
}
class NetForCircum {
int cell = 8;
PVector size = new PVector(0, 0);
IntList[][] objectsInCell = new IntList[cell][cell];
NetForCircum(ArrayList<Circum> cir)
{
size.x = width/cell;
size.y = height/cell;
for (int i = 0; i<cell; i++)
{
for (int j = 0; j<cell; j++)
{
objectsInCell[i][j] = new IntList();
}
}
for (int i = 0; i<cir.size() - 1; i++)
{
float pozLeft = cir.get(i).point.x - cir.get(i).radius, pozRight = cir.get(i).point.x + cir.get(i).radius, pozUp = cir.get(i).point.y - cir.get(i).radius, pozDown = cir.get(i).point.y + cir.get(i).radius;
for (int j = 1; j<=cell; j++)
{
for (int k = 1; k<=cell; k++)
{
float curentSizeX = size.x * j, curentSizeY = size.y * k, previousSizeX = size.x * (j - 1), previousSizeY = size.y * (k - 1);
if ((pozLeft>previousSizeX && pozRight<curentSizeX && pozUp>previousSizeY && pozDown<curentSizeY) || (cir.get(i).point.x>previousSizeX && cir.get(i).point.x<curentSizeX && cir.get(i).point.y>previousSizeY && cir.get(i).point.y<curentSizeY))
{
cir.get(i).cellNumber.add(new PVector(j, k));
cir.get(i).cellBorderX.set(previousSizeX, curentSizeX);
cir.get(i).cellBorderY.set(previousSizeY, curentSizeY);
objectsInCell[j-1][k-1].append(i);
}
}
}
}
}
}
除了@Rabbid76 的出色回答之外,我還建議避免循環兩次(例如檢查 i 和 j,然后檢查 j 和 i):
void checkForCollision()
{
final int numCircles = cir.size();
for(int i = 0; i < numCircles - 1; i++)
{
Circum circumI = cir.get(i);
for(int j = i + 1; j < numCircles; j++)
{
Circum circumJ = cir.get(j);
float dx = circumJ.point.x - circumI.point.x;
float dy = circumJ.point.y - circumI.point.y;
float distanceSquared = ((dx * dx) + (dy * dy));
float radii = circumJ.radius + circumI.radius;
float thresholdDistanceSquared = radii * radii;
if(distanceSquared < thresholdDistanceSquared){
//collision(circumI, circumJ, ...)
}
}
}
}
我很久以前就從 actionscript 中的 Keith Peter 的 Making Things Move中學到了這一點,其中每一點性能都很重要。 還要注意 object 屬性如何只被訪問一次並緩存到局部變量中以供重復使用。 這是另一個習慣,因為在 actionscript(或 javascript)虛擬機中訪問嵌套數據(getter)的成本很高。 Java 虛擬機可能效率更高一些,這可能不是必需的。
我還強烈建議將優化放在最后,並使用VisualVM等分析工具來確定要優化的內容。 您指出的是一個很好的候選者,但可能還有其他地方需要研究。 從最慢的開始,您可能需要觸摸 rest。
例如,根據 pastebin 代碼,圓和線的渲染看起來有點慢。 您可以在Processing > Examples > Demos > Performance中查看使用PShape
/ createShape(ELLIPSE)
和 Particle 示例
一個廉價的優化是比較距離的平方而不是距離。 對於歐氏距離的計算,需要平方根:
distance = sqrt( (x2-x1) ^ 2 + (y2-y1) ^ 2 )
即使對於今天的計算機來說,計算平方根也是非常昂貴的。 對於距離的平方,不需要平方根:
distance_square = (x2-x1) ^ 2 + (y2-y1) ^ 2
使用magSq()
而不是mag()
並將其與min_dyst*min_dyst
而不是min_dyst
進行比較:
PVector lengthFrom_i_to_j= PVector.sub( cir.get(j).point, cir.get(i).point);
// Calculates the magnitude (length) of the vector, squared.
float oldDistSq = lengthFrom_i_to_j.magSq();
float min_dyst = cir.get(j).radius + cir.get(i).radius;
// Compare squared distances
if (oldDistSq <= min_dyst * min_dyst) {
// [...]
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.