我发出了一些挑战,并认为我可以站出来寻求帮助.我想用 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; }