我发出了一些挑战,并认为我可以站出来寻求帮助.我想用 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数组,但仍然会收敛于最后一个点.
有人在乎称重吗?
我认为这是一种相当简单,准确和优雅的方法.它采用分而治之的策略.仅从2个值开始:>起点
>终点
计算中点.将中点偏移一些值方差(可以相对于长度计算).理想情况下,偏移应该是连接起点和终点的矢量的法线,但是只要你的螺栓大部分垂直移动,就像真正的闪电一样,你可以通过使这个偏移水平来便宜.对于(start,offset_mid)和(offset_mid,end)重复上述过程,但这次使用较小的数字进行方差.这是递归方法,其可以在达到阈值方差或阈值线段长度时终止.当递归展开时,您可以绘制所有连接器段.这个想法是最大的方差发生在螺栓的中心(当开始到结束的距离最长时),并且每次递归调用时,点之间的距离会缩小,方差也会缩小.这样,螺栓的全局方差将远大于任何局部方差(如真正的闪电).
这是使用该算法从相同的预定点生成的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;
}
