4

我向自己发出了一种挑战,并认为我可以站起来寻求帮助以解决这个问题。我想使用 java Graphics 绘制看起来像闪电击中给定点的东西。

现在我只有这个,它向随机方向发射廉价的“闪电”,我不在乎它最终会在哪里结束。

lightning[0] = new Point(370,130); //This is a given start point.

// Start in a random direction, each line segment has a length of 25
double theta = rand.nextDouble()*2*Math.PI;
int X = (int)(25*Math.cos(theta));
int Y = (int)(25*Math.sin(theta));

//Populate the array with more points
for (int i = 1 ; i < lightning.length ; i++)
{
  lightning[i] = new Point(X + lightning[i-1].x, Y + lightning[i-1].y);

  boolean plusminus = rand.nextBoolean();
  if (plusminus) theta = theta + rand.nextDouble()*(Math.PI/2);
  else theta = theta - rand.nextDouble()*(Math.PI/2);

  X = (int)(25*Math.cos(theta));
  Y = (int)(25*Math.sin(theta));
}

// Draw lines connecting each point
canvas.setColor(Color.WHITE);
for (int i = 1 ; i < lightning.length ; i++)
{
  int Xbegin = lightning[i-1].x;
  int Xend = lightning[i].x;
  int Ybegin = lightning[i-1].y;
  int Yend = lightning[i].y;

  canvas.drawLine(Xbegin, Ybegin, Xend, Yend);

  //if (Xend != Xbegin) theta = Math.atan((Yend - Ybegin)/(Xend - Xbegin));

  // Restrict the angle to 90 degrees in either direction
  boolean plusminus = rand.nextBoolean();
  if (plusminus) theta = theta + rand.nextDouble()*(Math.PI/2);
  else theta = theta - rand.nextDouble()*(Math.PI/2);

  // 50/50 chance of creating a half-length off-shoot branch on the end
  if (rand.nextBoolean())
  {
    int Xoff = (int)(Xend+(12*Math.cos(theta)));
    int Yoff = (int)(Yend+(12*Math.sin(theta)));

    canvas.drawLine(Xend, Yend, Xoff, Yoff);
  }
}

我试图想出一些类似的方法来创建这种效果,但是预先定义了数组中的最后一个点,这样闪电就可以“击中”一个特定的点。换句话说,我想以一种随机的方式填充 Point 数组,但仍会收敛到一个最终点。

有人愿意称重吗?

4

2 回答 2

4

我认为这是相当简单、准确和优雅的方法。它使用分而治之的策略。仅从 2 个值开始:

  • 起点
  • 终点

计算中点。将该中点偏移一些值variance(可以相对于长度计算)。理想情况下,偏移量应该垂直于连接起点和终点的矢量,但是只要你的螺栓大部分垂直移动,就像真正的闪电一样,你可以通过使偏移量水平来降低成本。对 (start, offset_mid) 和 (offset_mid, end) 重复上述过程,但这次使用较小的数字variance. 这是一种递归方法,可以在达到阈值方差或阈值线段长度时终止。随着递归展开,您可以绘制所有连接器段。这个想法是最大的方差发生在螺栓的中心(当开始到结束的距离最长时),并且随着每次递归调用,点之间的距离会缩小,方差也会缩小。这样,闪电的全局方差将远大于任何局部方差(就像真正的闪电一样)。

这是使用该算法从相同的预定点生成的 3 个不同螺栓的图像。这些点恰好是 (250,100) 和 (500,800)。如果您想要沿任何方向移动的螺栓(不仅仅是“大部分垂直”),那么您需要向点移动代码添加更多复杂性,根据螺栓的移动角度移动 X 和 Y。

闪电

这里有一些用于这种方法的 Java 代码。我使用了一个,ArrayList因为分而治之的方法并不提前知道最终会有多少元素。

// play with these values to fine-tune the appearance of your bolt
private static final double VAR_FACTOR = 0.40;
private static final double VAR_DECREASE = 0.55;
private static final int MIN_LENGTH = 50;

public static ArrayList<Point> buildBolt(Point start, Point end) {
    ArrayList<Point> bolt = new ArrayList<Point>();
    double dx = start.getX() - end.getX();
    double dy = start.getY() - end.getY();
    double length = Math.sqrt(dx*dx + dy*dy);
    double variance = length * VAR_FACTOR;
    bolt.add(start);
    buildBolt(start, end, bolt, variance);
    return bolt;
}

private static void buildBolt(Point start, Point end,
                              List<Point> bolt, double variance) {
    double dx = start.getX() - end.getX();
    double dy = start.getY() - end.getY();
    double length = Math.sqrt(dx*dx + dy*dy);
    if (length > MIN_LENGTH) {        
        int varX = (int) ((Math.random() * variance * 2) - variance);
        int midX = (start.x + end.x)/2 + varX;
        int midY = (start.y + end.y)/2;
        Point mid = new Point(midX, midY);
        buildBolt(start, mid, bolt, variance * VAR_DECREASE);
        buildBolt(mid, end, bolt, variance * VAR_DECREASE);
    } else {
        bolt.add(end);
    }
    return;      
}
于 2012-12-05T18:58:02.960 回答
1

没有任何图形经验,我有这样的建议:很难选择一个特定的点,然后尝试以“随机”的方式到达它。相反,我建议创建一条从起点到终点的直线,然后随机弯曲其中的一部分。您可以进行多次通过,将越来越小的段弯曲到一定的极限以获得所需的外观。同样,我在没有任何图形 API 知识的情况下这么说。

于 2012-12-05T18:52:02.740 回答