Some time ago I made a lighting bolt effect in Java, using Slick2D library, following the tutorial of Drilian’s House of Game Development. My results:

If you are looking to make a nice lighting bolt effect for your game, I recommend you to follow the original tutorial.

Here is my code if you want to use it and/or modify it:

package com.gemserk.commons.tests;

import static org.lwjgl.opengl.GL11.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
import java.util.concurrent.Callable;

import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Line;
import org.newdawn.slick.geom.Vector2f;
import org.newdawn.slick.opengl.SlickCallable;

public class LightingBoltTestTemporal extends BasicGame {

	public LightingBoltTestTemporal(String title) {
		super(title);
	}

	public static void main(String[] arguments) throws SlickException {
		AppGameContainer app = new AppGameContainer(new LightingBoltTestTemporal("Name");
		app.setDisplayMode(320, 240, false);
		app.setAlwaysRender(true);
		app.setMinimumLogicUpdateInterval(1);
		app.setShowFPS(true);
		app.start();
		return app;
	}

	public static class LightingBoltEffect {

		Collection<Line> segments;

		int totalTime;

		int currentTime;

		private float lineWidth;

		public LightingBoltEffect(int time, Collection<Line> segments, float lineWidth) {
			this.totalTime = time;
			this.segments = segments;
			this.currentTime = time;
			this.lineWidth = lineWidth;
		}

		public void update(int delta) {
			currentTime -= delta;
			if (currentTime <= 0)
				currentTime = 0;
		}

		public void render() {
			float alpha = (float) currentTime / (float) totalTime;
			glPushMatrix();
			glColor4f(alpha, alpha, alpha, alpha);
			glLineWidth(lineWidth);
			glBegin(GL_LINES);
			{
				for (Line segment : segments) {
					glVertex(segment.getStart());
					glVertex(segment.getEnd());
				}
			}
			glEnd();
			glPopMatrix();
		}

		public boolean isDone() {
			return currentTime <= 0;
		}
		

		public void glVertex(Vector2f v) {
			glVertex3f(v.x, v.y, 0);
		}
		
	}

	@Override
	public void init(GameContainer container) throws SlickException {
		generateLightingBolt(new Vector2f(50, 240), new Vector2f(290, 240), 100);
	}

	protected void generateLightingBolt(Vector2f p0, Vector2f p1, int duration) {
		Collection<Line> segments = new ArrayList<Line>();
		
		segments.add(new Line(p0, p1));
		
		float offset = 200f;
		double probability = 0.3; // probability to generate new partitions
		float height = 50.0f; 
		
		Random random = new Random();
		
		int partitions = 4;
		
		for (int i = 0; i < partitions; i++) {
		
			Collection<Line> newSegments = new ArrayList<Line>();
		
			for (Line segment : segments) {
		
				Vector2f midPoint = segment.getStart().copy().add(segment.getEnd()).scale(0.5f);
		
				Vector2f perpendicular = midPoint.copy().add(90);
				perpendicular.normalise().scale(random.nextFloat() * offset - (offset / 2));
				midPoint.add(perpendicular);
				
				if (random.nextFloat() < probability) {
					// generate new branch
					Vector2f direction = midPoint.copy().sub(segment.getStart());
					direction.add(random.nextFloat() * height);
					newSegments.add(new Line(midPoint.copy(), midPoint.copy().add(direction)));
				}
		
				newSegments.add(new Line(segment.getStart().copy(), midPoint.copy()));
				newSegments.add(new Line(midPoint.copy(), segment.getEnd().copy()));
			}
		
			segments = newSegments;
		
			offset /= 2;
		}
		lightingBoltEffect = new LightingBoltEffect(duration, segments, 2.0f);
	}

	private LightingBoltEffect lightingBoltEffect;

	@Override
	public void update(GameContainer container, int delta) throws SlickException {
		lightingBoltEffect.update(delta);
		if (!lightingBoltEffect.isDone())
			return;

		Input input = container.getInput();
		if (!input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON))
			return;

		int mouseX = input.getMouseX();
		int mouseY = input.getMouseY();

		Random random = new Random();
		int duration = random.nextInt() % 600 + 100;
		generateLightingBolt(new Vector2f(mouseX, mouseY), new Vector2f((mouseX + 300), mouseY), duration);
	}

	@Override
	public void render(GameContainer container, Graphics g) throws SlickException {
		SlickCallable.enterSafeBlock();
		lightingBoltEffect.render();
		SlickCallable.leaveSafeBlock();
	}
}