Actionscript 3 – as3 Lightning / Thunderbolt / Electric discharge Class

actionscript 3, algorithms, BitmapData, classes, fun, Math, morphing, perlinNoise, simulation

Finally here we come!

Yup, sry for the delay, I’ve had a lot of work recently.

I have prepared three demos and a publishable (but far from perfect and not yet documented) class. The demos are FLA based… you can find the timeline code to assemble the demos at the bottom of the post. I’ll publish some documentation in the next days, so until then just look at the demos’ code to unserstand the basic of the class usage.

Download Lightning classes

Demo N°1:
This demo shows the two different behaviours the class can mimic: Electric discharge/beam or lightning. Drag the ball near or far to the coil to see different behaviors.


Click to start

Demo N°2:
This demos show the maxLength and maxLengthVary properties in action.
Bring the fingers near to the plug to have continuos electricity. Bringing the hand far from the plug lowers the discharge probability. Reaching the max distance simply disables it.


Click to start

Demo N°3:
This demo is a good reason for the publishing delay :P

A nice sandbox to play with (some of) the properties.
The class is recursive to create children so many properties have also a decay twin property which rule how the property is passed to children.
As instance if you set a childrenMaxCount = 6 to the main Lightning instance it will have a maximum of 6 direct children. Its children will have a childrenMaxCount value which depends on the main instance childrenMaxCount and childrenMaxCountDecay.
So if you set childrenMaxCount = 6 and childrenMaxCountDecay = .5 the children of the main instance will have childrenMaxCount = 3.
If you set childrenMaxCount = 6 and childrenMaxCountDecay = 0 the children of the main instance will have childrenMaxCount = 6 (no decay).

This value can be very useful to optimize the speed of execution cause smaller branches don’t need many children or many steps of detail.


Click to start

Ok, I’m too tired to write more. I’ll publish some documentation in the next days.
Feel free to ask everything question you can have in the comments, and as usual if you like this stuff scream it in the comments!

Demos’ code after the break. Waiting for your comments I will surf through the website of fatcow and see if they have any good hosting plans.

Demos code is just timeline code to instance and pilot the lightning class… and very untidy! Please don’t blame it :D

Demo N°1:

import com.oaxoa.fx.Lightning;
import com.oaxoa.fx.LightningFadeType;

const cx:uint=360;
const cy:uint=320;

var color:uint=0xffffff;
var ll:Lightning=new Lightning(color, 2);
ll.blendMode=BlendMode.ADD;
ll.childrenDetachedEnd=true;
ll.childrenLifeSpanMin=.1;
ll.childrenLifeSpanMax=2;
ll.childrenMaxCount=4;
ll.childrenMaxCountDecay=.5;
ll.steps=150;
ll.alphaFadeType=LightningFadeType.TIP_TO_END;

ball.useHandCursor=ball.buttonMode=true;
dot1.mouseEnabled=dot2.mouseEnabled=false;
dot1.alpha=.75;

var glow:GlowFilter=new GlowFilter();
glow.color=color;
glow.strength=3.5;
glow.quality=3;
glow.blurX=glow.blurY=10;
ll.filters=dot1.filters=dot2.filters=[glow];
addChild(ll);

ll.childrenProbability=.3;

var p:Point=new Point();
randomizePoint();
function randomizePoint():void {
	var angle:Number=-Math.random()*Math.PI;
	var dist:Number=160+Math.random()*180;
	p.x=cx+Math.cos(angle)*dist;
	p.y=cy+Math.sin(angle)*dist;
}

addEventListener(Event.ENTER_FRAME, onframe);
function onframe(event:Event):void {
	
	var rnd:Number=Math.random();
	if(rnd<.05) randomizePoint();
	var dx:Number=cx-ball.x;
	var dy:Number=cy-ball.y;
	var d:Number=Math.sqrt(dx*dx+dy*dy);
	if(d<310) {
		dot2.visible=true;
		if(ll.childrenDetachedEnd) {
			ll.childrenDetachedEnd=false;
			ll.alphaFadeType=LightningFadeType.GENERATION;
			ll.killAllChildren();
		}
		
		ll.endX=dot2.x=ball.x;
		ll.endY=dot2.y=ball.y;
	} else {
		dot2.visible=false;
		if(!ll.childrenDetachedEnd) {
			ll.childrenDetachedEnd=true;
			ll.alphaFadeType=LightningFadeType.TIP_TO_END;
			ll.killAllChildren();
		}
		ll.endX=p.x;
		ll.endY=p.y;
	}
	var ddx:Number=cx-ll.endX;
	var ddy:Number=cy-ll.endY;
	var aangle:Number=Math.atan2(ddy, ddx);
	ll.startX=cx-Math.cos(aangle)*80;
	dot1.scaleX=Math.sin(aangle);
	ll.startY=cy;
	dot1.x=ll.startX;
	dot1.y=ll.startY;
	ll.update();
}

ball.addEventListener(MouseEvent.MOUSE_DOWN, onmdown);
function onmdown(event:MouseEvent):void {
	ball.startDrag();
}
ball.addEventListener(MouseEvent.MOUSE_UP, onmup);
function onmup(event:MouseEvent):void {
	ball.stopDrag();
}

Demo N°2:

import com.oaxoa.fx.Lightning;
import com.oaxoa.fx.LightningFadeType;

setChildIndex(fingers, 2);

var iy:Number=fingers.y;
addEventListener(MouseEvent.MOUSE_MOVE, onmove);

fingers.x=fingers.y/2.5-10;

function updatePositions():void {
	ll.endX=fingers.x+fingers.dot1.x;
	ll.endY=fingers.y+fingers.dot1.y;
	ll2.endX=fingers.x+fingers.dot2.x;
	ll2.endY=fingers.y+fingers.dot2.y;
}

function onmove(event:MouseEvent):void {
	fingers.y=mouseY-150;
	if(fingers.y320) fingers.y=320;
	fingers.x=fingers.y/2.5-10;
	updatePositions();
	event.updateAfterEvent();
}
addEventListener(Event.ENTER_FRAME, onframe);
function onframe(event:Event):void {
	ll.update();
	ll2.update();
}

var color:uint=0xddeeff;
var ll:Lightning=new Lightning(color, 2);
var ll2:Lightning=new Lightning(color, 2);
ll.blendMode=ll2.blendMode=BlendMode.ADD;
ll.childrenProbability=ll2.childrenProbability=.5;
ll.childrenLifeSpanMin=ll2.childrenLifeSpanMin=.1;
ll.childrenLifeSpanMax=ll2.childrenLifeSpanMax=2;
ll.maxLength=ll2.maxLength=50;
ll.maxLengthVary=ll2.maxLengthVary=200;

ll.startX=dot3.x;
ll.startY=dot3.y;
ll2.startX=dot4.x;
ll2.startY=dot4.y;

var glow:GlowFilter=new GlowFilter();
glow.color=color;
glow.strength=3.5;
glow.quality=3;
glow.blurX=glow.blurY=10;
ll.filters=ll2.filters=[glow];
addChild(ll);
addChild(ll2);

updatePositions();

Demo N°3:
(The ugliest bunch of random code lines ever written :D )

import com.oaxoa.fx.Lightning;
import com.oaxoa.fx.LightningFadeType;
import com.oaxoa.components.ToolTip;
import fl.controls.Button;
import fl.data.DataProvider;

import fl.events.SliderEvent;
var color:uint=0xffffff;
var ll:Lightning=new Lightning(color, 2);
ll.blendMode=BlendMode.ADD;

var glow:GlowFilter=new GlowFilter();
glow.color=color;
glow.strength=4;
glow.quality=3;
glow.blurX=glow.blurY=10;
ll.filters=[glow];
addChild(ll);
ll.startX=cross1.x;
ll.startY=cross1.y;

ll.endX=cross2.x;
ll.endY=cross2.y;

setChildIndex(ll,0);

ll.childrenMaxGenerations=3;
ll.childrenMaxCountDecay=.5;

addEventListener(Event.ENTER_FRAME, onframe);
function onframe(event:Event):void {
	ll.startX=cross1.x;
	ll.startY=cross1.y;
	
	ll.endX=cross2.x;
	ll.endY=cross2.y;
	ll.update();
	updateCircles();
}

import com.oaxoa.components.FrameRater;
var fr:FrameRater=new FrameRater(0xffffff, true);
addChild(fr);

var ttip:ToolTip=new ToolTip();
addChild(ttip);

var tfmt:TextFormat=new TextFormat("_sans", 11, 0xffffff);

cb0.addItem({label:"Choose a preset", value:0});
cb0.addItem({label:"Fast discharge", value:1});
cb0.addItem({label:"Fast discharge (Max length + max length variation)", value:2});
cb0.addItem({label:"Fast discharge (slow-motion)", value:3});
cb0.addItem({label:"Moving Thunderbolt", value:4});
cb0.addItem({label:"Moving Thunderbolt (Max length + max length variation)", value:5});
cb0.selectedIndex=0;
cb0.addEventListener(Event.CHANGE, oncb);
cb0.textField.setStyle("textFormat", tfmt);
cb0.dropdown.setRendererStyle("textFormat", tfmt);

cb1.addItem({label:"Discharge", value:false});
cb1.addItem({label:"Lightning (detached end)", value:true});
cb1.selectedIndex=1;
cb1.addEventListener(Event.CHANGE, oncb);
cb1.textField.setStyle("textFormat", tfmt);
cb1.dropdown.setRendererStyle("textFormat", tfmt);

cb2.addItem({label:"None", value:LightningFadeType.NONE});
cb2.addItem({label:"Generation", value:LightningFadeType.GENERATION});
cb2.addItem({label:"Tip to end", value:LightningFadeType.TIP_TO_END});
cb2.selectedIndex=2;
cb2.addEventListener(Event.CHANGE, oncb);
cb2.textField.setStyle("textFormat", tfmt);
cb2.dropdown.setRendererStyle("textFormat", tfmt);

cb3.addItem({label:"None", value:LightningFadeType.NONE});
cb3.addItem({label:"Generation", value:LightningFadeType.GENERATION});
cb3.addItem({label:"Tip to end", value:LightningFadeType.TIP_TO_END});
cb3.selectedIndex=2;
cb3.addEventListener(Event.CHANGE, oncb);
cb3.textField.setStyle("textFormat", tfmt);
cb3.dropdown.setRendererStyle("textFormat", tfmt);

function oncb(event:Event):void {
	var t:ComboBox=event.currentTarget as ComboBox;
	switch(t) {
		case cb0:
			setPreset(t.selectedItem.value);
			break;
		case cb1:
			ll.childrenDetachedEnd=t.selectedItem.value;
			ll.killAllChildren();
			break;
		case cb2:
			ll.alphaFadeType=t.selectedItem.value;
			ll.killAllChildren();
			break;
		case cb3:
			ll.thicknessFadeType=t.selectedItem.value;
			ll.killAllChildren();
			break;
	}
}


slider.addEventListener(SliderEvent.CHANGE, onslider);
slider2.addEventListener(SliderEvent.CHANGE, onslider);
slider3.addEventListener(SliderEvent.CHANGE, onslider);
slider4.addEventListener(SliderEvent.CHANGE, onslider);
slider5.addEventListener(SliderEvent.CHANGE, onslider);
slider6.addEventListener(SliderEvent.CHANGE, onslider);
slider7.addEventListener(SliderEvent.CHANGE, onslider);
slider8.addEventListener(SliderEvent.CHANGE, onslider);
slider9.addEventListener(SliderEvent.CHANGE, onslider);
slider10.addEventListener(SliderEvent.CHANGE, onslider);
slider11.addEventListener(SliderEvent.CHANGE, onslider);
slider12.addEventListener(SliderEvent.CHANGE, onslider);
slider13.addEventListener(SliderEvent.CHANGE, onslider);
function onslider(event:SliderEvent):void {
	var t:Slider=event.currentTarget as Slider;
	ttip.show(t.value.toString());
	ttip.y=t.y-30;
	switch(t) {
		case slider:
			ll.smoothPercentage=t.value;
			break;
		case slider2:
			ll.childrenAngleVariation=t.value;
			break;
		case slider3:
			ll.childrenMaxCount=t.value;
			break;
		case slider4:
			ll.wavelength=t.value;
			break;
		case slider5:
			ll.amplitude=t.value;
			break;
		case slider6:
			ll.speed=t.value;
			break;
		case slider7:
			ll.thickness=t.value;
			ll.killAllChildren();
			break;
		case slider8:
			ll.maxLength=t.value;
			break;
		case slider9:
			ll.maxLengthVary=t.value;
			break;
		case slider10:
			ll.childrenProbability=t.value;
			ll.killAllChildren();
			break;
		case slider11:
			ll.childrenLifeSpanMin=t.value;
			ll.killAllChildren();
			if(t.value>slider12.value) slider12.value=t.value;
			break;
		case slider12:
			ll.childrenLifeSpanMax=t.value;
			ll.killAllChildren();
			slider11.visible=t.value!=0;
			break;
		case slider13:
			ll.steps=t.value;
			ll.killAllChildren();
			break;
	}
	ll.render();
}

function setPreset(n:uint):void {
	switch(n) {
		// fast discharge
		case 1:
			ll.childrenLifeSpanMin=1;
			ll.childrenLifeSpanMax=3;
			ll.childrenProbability=1;
			ll.childrenMaxGenerations=3;
			ll.childrenMaxCount=4;
			ll.childrenAngleVariation=110;
			ll.thickness=2;
			ll.steps=100;
			
			ll.smoothPercentage=50;
			ll.wavelength=.3;
			ll.amplitude=.5;
			ll.speed=.7;
			ll.maxLength=0;
			ll.maxLengthVary=0;
			
			ll.childrenDetachedEnd=false;
			cb1.selectedIndex=0;
			ll.alphaFadeType=LightningFadeType.GENERATION;
			cb2.selectedIndex=1;
			ll.thicknessFadeType=LightningFadeType.NONE;
			cb3.selectedIndex=0;
			
			break;
		// fast discharge (with max length+variation)
		case 2:
			ll.childrenLifeSpanMin=1;
			ll.childrenLifeSpanMax=3;
			ll.childrenProbability=1;
			ll.childrenMaxGenerations=3;
			ll.childrenMaxCount=4;
			ll.childrenAngleVariation=110;
			ll.thickness=2;
			ll.steps=100;
			
			ll.smoothPercentage=50;
			ll.wavelength=.3;
			ll.amplitude=.5;
			ll.speed=.7;
			ll.maxLength=440;
			ll.maxLengthVary=75;
			
			ll.childrenDetachedEnd=false;
			cb1.selectedIndex=0;
			ll.alphaFadeType=LightningFadeType.GENERATION;
			cb2.selectedIndex=1;
			ll.thicknessFadeType=LightningFadeType.NONE;
			cb3.selectedIndex=0;
			
			break;
		// fast discharge slowmo
		case 3:
			ll.childrenLifeSpanMin=1;
			ll.childrenLifeSpanMax=3;
			ll.childrenProbability=1;
			ll.childrenMaxGenerations=3;
			ll.childrenMaxCount=4;
			ll.childrenAngleVariation=110;
			ll.thickness=2;
			ll.steps=100;
			
			ll.smoothPercentage=50;
			ll.wavelength=.3;
			ll.amplitude=.5;
			ll.speed=.1;
			ll.maxLength=0;
			ll.maxLengthVary=0;
			
			ll.childrenDetachedEnd=false;
			cb1.selectedIndex=0;
			ll.alphaFadeType=LightningFadeType.GENERATION;
			cb2.selectedIndex=1;
			ll.thicknessFadeType=LightningFadeType.NONE;
			cb3.selectedIndex=0;
			
			break;
		// moving thumnder
		case 4:
			ll.childrenLifeSpanMin=.1;
			ll.childrenLifeSpanMax=2;
			ll.childrenProbability=1;
			ll.childrenMaxGenerations=3;
			ll.childrenMaxCount=4;
			ll.childrenAngleVariation=130;
			ll.thickness=3;
			ll.steps=100;
			
			ll.smoothPercentage=50;
			ll.wavelength=.3;
			ll.amplitude=.5;
			ll.speed=1;
			ll.maxLength=0;
			ll.maxLengthVary=0;
			
			ll.childrenDetachedEnd=true;
			cb1.selectedIndex=1;
			ll.alphaFadeType=LightningFadeType.TIP_TO_END;
			cb2.selectedIndex=2;
			ll.thicknessFadeType=LightningFadeType.GENERATION;
			cb3.selectedIndex=1;
			
			break;
		case 5:
			ll.childrenLifeSpanMin=.1;
			ll.childrenLifeSpanMax=2;
			ll.childrenProbability=1;
			ll.childrenMaxGenerations=3;
			ll.childrenMaxCount=4;
			ll.childrenAngleVariation=130;
			ll.thickness=3;
			ll.steps=100;
			
			ll.smoothPercentage=50;
			ll.wavelength=.3;
			ll.amplitude=.5;
			ll.speed=1;
			ll.maxLength=440;
			ll.maxLengthVary=75;
			
			ll.childrenDetachedEnd=true;
			cb1.selectedIndex=1;
			ll.alphaFadeType=LightningFadeType.TIP_TO_END;
			cb2.selectedIndex=2;
			ll.thicknessFadeType=LightningFadeType.GENERATION;
			cb3.selectedIndex=1;
			
			break;
	}
	ll.killAllChildren();
	updateSliders();
}
function updateSliders():void {
	slider.value=ll.smoothPercentage;
	slider2.value=ll.childrenAngleVariation;
	slider3.value=ll.childrenMaxCount;
	slider4.value=ll.wavelength;
	slider5.value=ll.amplitude;
	slider6.value=ll.speed;
	slider7.value=ll.thickness;
	slider8.value=ll.maxLength;
	slider9.value=ll.maxLengthVary;
	slider10.value=ll.childrenProbability;
	slider11.value=ll.childrenLifeSpanMin;
	slider12.value=ll.childrenLifeSpanMax;
	slider13.value=ll.steps;
}
///////////////////

var tf:TextFormat=new TextFormat();
tf.color=0xffffff;

cross1.addEventListener(MouseEvent.MOUSE_UP, onup);
cross1.addEventListener(MouseEvent.MOUSE_DOWN, ondown);
cross2.addEventListener(MouseEvent.MOUSE_UP, onup);
cross2.addEventListener(MouseEvent.MOUSE_DOWN, ondown);
cross1.buttonMode=cross2.buttonMode=cross1.useHandCursor=cross2.useHandCursor=true;

function ondown(event:MouseEvent):void {
	event.currentTarget.alpha=.2;
	event.currentTarget.startDrag();
}
function onup(event:MouseEvent):void {
	event.currentTarget.alpha=1;
	event.currentTarget.stopDrag();
}
var circles:Shape=new Shape();
addChildAt(circles, 0);

function updateCircles():void {
	circles.graphics.clear();
	if(ll.maxLength>0) {
		circles.graphics.lineStyle(6, 0xffffff, .3);
		circles.graphics.drawCircle(cross1.x, cross1.y, ll.maxLength);
		circles.graphics.lineStyle(2, 0xffffff, .4);
		circles.graphics.drawCircle(cross1.x, cross1.y, ll.maxLength+ll.maxLengthVary);
		var steps:uint=5;
		for(var i:uint=1; i
			
86 Comments

79 Comments

  1. ethan  •  Jul 28, 2009 @2:16 am

    hey! that looks like the kind of code i write!

    impressive work though Pierluigi

  2. katopz  •  Jul 28, 2009 @5:31 am

    thx! it’s coooooooooooool ever! i love it :D

  3. localToGlobal  •  Jul 28, 2009 @8:53 am

    really awesome! i like it…

  4. Yugi  •  Jul 28, 2009 @4:54 pm

    Very cool. Thanks for sharing the code :)

  5. Og2t  •  Jul 28, 2009 @5:56 pm

    Wow, it’s great, I loved the example with fingers :) Would be nice to add some synchronised sound fx (generated as well), wondering how difficult it would be?

  6. Badger Manufacture  •  Jul 29, 2009 @12:59 am

    Amazing effect!! It has way more features than I’d been guessing about too. Really good Panta, I can’t wait to experiement with your well organised code. :)

  7. Winney  •  Jul 30, 2009 @3:45 am

    Best lightning effect ever!! Many thanks!

  8. Vlad  •  Jul 31, 2009 @6:31 pm

    Very well done. I downloaded the classes and I’ll give it a very good look, but before I do it, I have a question: are you drawing it to a BitmapData object?

  9. Maha  •  Jul 31, 2009 @6:54 pm

    Wow…great to see an awesome AS3 blog! Loved the lightning!

  10. Denis_s  •  Aug 10, 2009 @7:17 pm

    Sweet lightning!!! Came in perfect for a project I’m working on.
    I’ll send a link once it’s working.

  11. Og2t  •  Aug 17, 2009 @3:42 pm

    Looks like someone had used your class already :)

    http://www.hellofromearth.net (adverts)

  12. Pierluigi Pesenti  •  Aug 17, 2009 @3:58 pm

    WOA! Super cool!!! :)

  13. Ruwan  •  Aug 21, 2009 @5:28 am

    Nice effect. Thank you for sharing.

  14. Jonno  •  Aug 21, 2009 @11:29 am

    Anyone have some good sound for this?

  15. Deepin3000  •  Aug 21, 2009 @4:04 pm

    wonderful. it’s a great work!

  16. TS  •  Aug 25, 2009 @5:54 pm

    omg it’s damn cool, thanks for sharing!

  17. David5  •  Aug 25, 2009 @10:24 pm

    Cool effect!

  18. Denis_s  •  Sep 3, 2009 @4:18 pm

    I used it here. go to ‘song list creator’ and you’ll see it in step 2
    http://www.gogurt.com

    thank you for sharing your source code!

  19. Pierluigi Pesenti  •  Sep 3, 2009 @6:44 pm

    Wow! Very nice application, and nice implementation too!! ;-)

  20. hai  •  Sep 10, 2009 @11:28 am

    so cool.

  21. paul  •  Sep 10, 2009 @5:51 pm

    hi, looks amazing!!
    but i cant get the demo’s to work..
    could you share your fla’s? please
    i would love to use this for my next short movie.
    thanks !

  22. Pierluigi Pesenti  •  Sep 11, 2009 @7:18 am

    hi Paul, it’s not about the fla. It contains only the code snippet I posted to import and instance the main class. Did you download and imported the class?
    Could you post any error you receive from the compiler?
    Bye

  23. paul  •  Sep 11, 2009 @12:24 pm

    ok. for example demo 2. i make a fla, add a document class, copy your demo code in there. i make fingers, dot1, dot2 movieclip symbols. add them to the stage even.
    then i run it. and i get errors regarding events and filters, so i import those. but then i get other errors. just one hopeless mess i get myself in.
    i must be missing something silly. you probably have an easy way to do it. but i cant figure it out.

    thanks for taking your time to help, much appreciated

  24. Pierluigi Pesenti  •  Sep 11, 2009 @1:50 pm

    No problem at all. Could you up your fla somewhere to let me have a look?
    Cheers

  25. paul  •  Sep 11, 2009 @5:42 pm

    finally i did get it to work. ^^ this is my code (stripped down to a minimum) in the document class.
    sorry to spam your blog with it.
    but i’m still wondering how you do it. it should be possible to copy/paste your demo-code and have it workable, right?


    package {
    import com.oaxoa.fx.Lightning;
    import com.oaxoa.fx.LightningFadeType;
    import flash.events.*;
    import flash.display.*;
    public class LightningFX2 extends MovieClip {
    var ll:Lightning;
    public function LightningFX2(){
    stage.addEventListener(MouseEvent.MOUSE_MOVE, onmove);
    addEventListener(Event.ENTER_FRAME, onframe);
    ll = new Lightning(0xFF6677, 2);
    addChild(ll);
    updatePositions();
    }
    function updatePositions():void {
    ll.endX = mouseX;
    ll.endY = mouseY;
    }
    function onmove(event:MouseEvent):void {
    updatePositions();
    }
    function onframe(event:Event):void {
    ll.update();
    }
    };
    };

  26. magno  •  Sep 18, 2009 @1:04 pm

    how did you do that can you publish a tutorial step by step please i just need it.

  27. Pierluigi Pesenti  •  Sep 18, 2009 @1:30 pm

    hey mango, there’s a full downloadable class, there are 3 examples with the relative source code, there are two previous posts explaining the logic behind this… I think I couldn’t explain it more :)

  28. lianrb  •  Sep 21, 2009 @1:44 am

    cool………

  29. Raghuanth  •  Sep 21, 2009 @8:59 am

    ok

  30. oliwen  •  Sep 27, 2009 @8:44 am

    Thanks!Cool effect!

  31. icefirefdp  •  Oct 14, 2009 @11:36 am

    awesome that’s very cool, it make me excited.i had copied your codes to flex builder and run it certainly change code littlely, i am researching your code,but i don’t understand some logic,please comment its logic the following is i dont understand, thank your for sharing your code.
    soff=(sbd.getPixel(i, 0)-0×808080)/0xffffff*len*multi2;
    soffx=Math.sin(angle)*soff;
    soffy=Math.cos(angle)*soff;

    boff=(bbd.getPixel(i, 0)-0×808080)/0xffffff*len*amplitude;
    boffx=Math.sin(angle)*boff;
    boffy=Math.cos(angle)*boff;

    tx=startX+dx/(steps-1)*i+soffx+boffx;
    ty=startY+dy/(steps-1)*i-soffy-boffy;

    thank you for writing back mail: icefirefdp@163.com

  32. Pierluigi Pesenti  •  Oct 14, 2009 @11:56 am

    There are two displacements to achieve the effect a small one (every var beginning with “s” and a big one “b”).

    /* small offset is calculated by getting pixel value from the small perlinNoise bitmapData (sbd) – medium grey (0×808080) so the value doesn’t range from 0 to 0xffffff but from -0×808080 to +0×808080 the normalized to -1 to +1 (dividing by 0xffffff) and multiplied for the length of the lightning (so is always proportioned when scaling it) and multiplied for the (fixed) multiplier (multi2).
    So all this is just to have a numeric value taken from the perlinNoised bitmapData*/
    soff=(sbd.getPixel(i, 0)-0×808080)/0xffffff*len*multi2;
    // the x offset is calculated upon the sin of the angle of the lightning * the small offset
    soffx=Math.sin(angle)*soff;
    // the same for the y using cosin
    soffy=Math.cos(angle)*soff;

    // do the same with the big offset except from that the big one is ruled by the amplitude parameter and not fixed.
    boff=(bbd.getPixel(i, 0)-0×808080)/0xffffff*len*amplitude;
    boffx=Math.sin(angle)*boff;
    boffy=Math.cos(angle)*boff;

    // finally the target X of the segment to draw is calculated starting from the beginning (startX) + the step length (dx/(steps-1) * i (and this would lead to a straight very normal line) the the small X offset and the big X offset are added to make the actual lightning.
    tx=startX+dx/(steps-1)*i+soffx+boffx;

    // same for the Y
    ty=startY+dy/(steps-1)*i-soffy-boffy;

    hope this helped :)

  33. tommy  •  Oct 20, 2009 @3:53 am

    Woo..It’s so cool

  34. awesome, it may be copy to use after some editing.
    Thanks for your sharing.

  35. Pierluigi Pesenti  •  Oct 26, 2009 @3:55 pm

    You can use it freely, as every piece of code I share here :-)

  36. swfDude  •  Oct 27, 2009 @9:43 pm

    1st worked great…cool, 2nd notWork…argh, error says:
    TypeError: Error #1010: A term is undefined and has no properties.
    at lightning2_fla::MainTimeline/updatePositions()
    at lightning2_fla::MainTimeline/onmove()

    thanx for code/ and any hep

  37. Meeeesta  •  Oct 30, 2009 @11:52 am

    Wow. Totally blown away.

    I was looking for a way to create a background animation that consists of morphing lines that didn’t hammer a viewer’s CPU. This looks the part. The effect I’m after is here, but without the macro variations, you’ve probably seen it before in abstract vector backgrounds (http://www.shutterstock.com/results.mhtml#photo_id=39720274 for example), almost parallel lines that bend and move like a ribbon.

    Without waffling on, what book’s would you recommend as reference for this kind of work? Are there any that you’d recommend? Especially for a Maths monkey. I’m going to try and pick at this to get the solution I want (before I have a mental break down and do another tween animation lol).

    Most all thanks for the inspiration, it’s a real find when you discover someone with massive talent willing to share their knowledge and experiences.

  38. Pierluigi Pesenti  •  Oct 30, 2009 @1:16 pm

    If it is a background animation, and you don’t want to hammer the CPU, you should move a single line with the kin of smooth movement you want, and draw it to a bitmap at everyframe, then darken the bitmap a little at every frame so the old lines progressively disappears. For the movement I could suggest to have a 1px*height px bitmapdata with a slowly moving perlinNoise. Then you should read all the pixels (or better get the vector) and use those values to draw your line.

    About the book, I am sorry since I an not the one who reads a lot of books, I learned by dashing my head against the wall until it works :-P , sometimes I look for some math articles online (understanding a very small percentage of them :D ).

    However try this: http://www.bit-101.com/blog/?p=2425
    I just bought it yesterday super discounted, not looked yet, but it seems promising.

    Thanks a lot for your appreciations.
    p.s.: You cannot come out with this… come back next week, since it’s quite interesting and we could try to do it together and then publish an article here ;)

  39. Meeeesta  •  Oct 30, 2009 @2:43 pm

    When I’m done unpicking what you’ve created and (if) I manage to get anything up and running (before I’m taken away by men in white coats) I’ll definitely drop you a line.

  40. Greg  •  Nov 5, 2009 @3:23 am

    SCREEEEEEEEEEEEEEEEAMING! *two thumbs up*
    How many walls did you broke with your head while making this? ;P

  41. Milan  •  Nov 10, 2009 @5:18 am

    hey mate,
    just wondering in the first demo how i would go by setting the lightning to go between two mc’s, i cant figure out how to change the coordinates, it just seems to drag my mc up into the corner, i managed to connect one (mindmc) but the other (powMc2) will connect but be dragged up into the top of the stage? i just wanted the lightning effect to join 2 motionless mc’s
    heres ur code hacked up
    [CODE]
    import com.oaxoa.fx.Lightning;
    import com.oaxoa.fx.LightningFadeType;

    const cx:uint=660;
    const cy:uint=320;

    var color:uint=0xffffff;
    var ll:Lightning=new Lightning(color, 2);
    ll.blendMode=BlendMode.ADD;
    ll.childrenDetachedEnd=true;
    ll.childrenLifeSpanMin=.1;
    ll.childrenLifeSpanMax=2;
    ll.childrenMaxCount=4;
    ll.childrenMaxCountDecay=.5;
    ll.steps=150;
    ll.alphaFadeType=LightningFadeType.TIP_TO_END;

    var glow:GlowFilter=new GlowFilter();
    glow.color=color;
    glow.strength=5;
    glow.quality=3;
    glow.blurX=glow.blurY=10;
    ll.filters=powMc1.filters=powMc2.filters=[glow];
    addChild(ll);

    ll.childrenProbability=.3;

    addEventListener(Event.ENTER_FRAME, onframe);
    function onframe(event:Event):void {

    var rnd:Number=Math.random();
    var dx:Number=cx-mindmc.x;
    var dy:Number=cy-mindmc.y;
    var d:Number=Math.sqrt(dx*dx+dy*dy);
    if(d<280) {
    powMc2.visible=true;
    if(ll.childrenDetachedEnd) {
    ll.childrenDetachedEnd=false;
    ll.alphaFadeType=LightningFadeType.GENERATION;
    ll.killAllChildren();
    }
    ll.endX=powMc2.x=mindmc.x;
    ll.endY=powMc2.y=mindmc.y;
    } else {
    powMc2.visible=false;
    if(!ll.childrenDetachedEnd) {
    ll.childrenDetachedEnd=true;
    ll.killAllChildren();
    }

    }
    var ddx:Number=cx-ll.endX;
    var ddy:Number=cy-ll.endY;
    powMc2.x=ll.startX;
    powMc2.y=ll.startY;
    ll.update();
    }
    [/CODE]

    please help meeee!

  42. Jimmy  •  Nov 27, 2009 @7:58 am

    Can you sent me you Demo2 Fla file
    thank you very much!!!

    my Email:jimmy.light@gmail.com

  43. takopus  •  Dec 1, 2009 @3:59 am

    Perfect! Just perfect! Thank you!

  44. aDoubleSo  •  Dec 1, 2009 @1:36 pm

    hi,
    this is great…
    i tried to convert this to flex 3, but i can’t add the Lightning-Objekt to the stage.
    when i try “Application.application.addChild(l1);” i get an UIComponent-exception.
    can anybody help me please!?

    thanks
    aDouble

  45. Pierluigi Pesenti  •  Dec 1, 2009 @1:47 pm

    You cannot simply add a Sprite to the stage, wrap it into a UIComponent.

  46. aDoubleSo  •  Dec 1, 2009 @1:53 pm

    thanks, i tried this first, but now it works … first time i get an null-pointer-exception. mayby i forgot to init the UIComponent…

    thanks

  47. Yan  •  Dec 19, 2009 @6:27 pm

    Thanks for share your code,They’re really cool,and this’s a piece of news come form Chinese friend.I hope we will be a good friend.
    My msn account is yanxingyang@hotmail.com

  48. tenchiwang  •  Jan 21, 2010 @10:08 am

    Lightning is useful~
    Good to share with the ~ thanks ~ ^ ^

  49. _mark  •  Jan 26, 2010 @11:08 pm

    dood, awesome job on this lightning effect! i’ll definitely let you know if i use the class! now watching ur blog :D

  50. elay  •  Mar 12, 2010 @1:03 pm

    Hi really rally great stuff.
    I am not so good in Flash.
    Is it possible to get the FLA File from the Demo 3 ??

    thanks alot

  51. weeeeeeeeeeeee  •  Apr 14, 2010 @11:14 am

    First of all I want to say GREAT WORK !
    I wanted to play a little with your results but I after downloaded the AS I don’t know what to create or what to do to see it and play with it.
    Please help :)

  52. me  •  Aug 31, 2010 @10:23 pm

    THIS IS SO AWESOME AND I JUST WANT TO LET YOU KNOW THAT I’M SCREAMING ABOUT IT IN THE COMMENTS YEAH W00T W00T CHICKEN FINGERS RANDOMNESS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  53. Alistor  •  Sep 1, 2010 @3:50 pm

    Increadible animation, I never saw something this close to an arc in flash. Could you please post the FLA file for those of us lamers who don’t know to work with classes?? :) )

  54. wynny  •  Oct 1, 2010 @10:01 am

    Thats awesome! thx for sharing!

  55. Roberto  •  Oct 17, 2010 @2:24 pm

    WOW!!! THANK YOU VERY MUCH FOR SHARING!!!

  56. svtor  •  Dec 10, 2010 @10:21 am

    Cool! this is very interesting and really good effect. Cheers

  57. Chris  •  Mar 25, 2011 @3:24 pm

    Hey thanks a lot for this nice effect. Used it here: http://www.native-instruments.com/#/en/?content=1505

  58. Jeff Monson  •  Mar 31, 2011 @5:17 pm

    Just ran across this in my searches for cool effects. I love the effect and am thinking of good use for it on the redesign of my site that’s due to be done mid April. This can be overlaid onto any image?

    Many thanks,
    Jeff Monson
    Webmaster – JLM Merchandise Surveillance and Security Products

  59. Pierluigi Pesenti  •  Mar 31, 2011 @9:52 pm

    Yes it can. Cya

  60. R. Cristi  •  Apr 2, 2011 @1:55 pm

    That was a very interesting piece of work. I am somewhat fascinated with electricity myself. If you have any more off-the-wall ideas, post it please

  61. Jeannie  •  Apr 7, 2011 @2:07 am

    This is really cool. What a great affect. I will have to show a relative that does experiments with electricity. He will get a kick out of it.

  62. Bette Stotelmyer  •  Apr 10, 2011 @5:25 am

    To Chris from NI: nice application of Panta’s efforts. If you’re associated with NI, I’m sure you appreciated all the controls. To Panta: I’m very unacquainted with all of this code, but I can’t help but leave big nose and hand prints on your site over this effect. Thanks for the show. Demo 2 shows how long the randomness of the lightening is sustained. I guess if I wished long enough and hard enough, I could get creative this way. You live in another world from the rest of us, helping to indistinguishably weld reality with virtuality .

  63. Villa  •  Apr 11, 2011 @4:25 pm

    Really great interactive effects – thanks for sharing

  64. FlashDeveloper  •  May 12, 2011 @8:27 pm

    Congratulation!
    Really great work.

    Can it be used commercial for free?

  65. Rufus  •  May 27, 2011 @1:00 am

    Hi.

    Please if any one can help me use that .as files.

    How to use them ? Where the files should be copied ?

    Thanks

  66. xavirobot  •  Sep 8, 2011 @7:02 am

    Greetings, I’m from Spain, I just wanted to say I find a great class and that I am using one of my projects as lightning gun.
    Congratulations for your work

    If you want to see results you can see it on youtube or on my blog

    youtube

    Blog

  67. Gabriel  •  Sep 10, 2011 @8:49 pm

    Really nice work. I’m looking at your code now. I feel like it needs to be a little more “out of the box”, if you know what I mean.

    1. I recommend a class in the package that would encapsulate the updating. This can be done via Event.ADDED_TO_STAGE / REMOVED_FROM_STAGE to detect if it is possible to add the Event.ENTER_FRAME, and when that event should be cleaned up.

    2. I like your presets from the 3rd example, why not have a package ‘presets’ that can be instantiated straight away?

    If I end up doing this myself, I’ll post the result here for your consideration.

    Thanks!

  68. Gabriel  •  Sep 11, 2011 @12:07 am

    Here’s an extention of the Lightning class that encapsulates the update functionality, the glow and the very useful setStart() and setEnd(). You can pass the stage, a point or a display object to these to tell it how the lightning should attach. If you pass the stage it will attach to the mouse.

    To use this class, do:

    addChild( new LightningPreset() );

    that’s it!

    package com.oaxoa.fx.presets
    {
    import com.oaxoa.fx.Lightning;
    import com.oaxoa.fx.LightningFadeType;

    import flash.display.*;
    import flash.events.*;
    import flash.filters.GlowFilter;
    import flash.geom.Point;

    public class LightningPreset extends Lightning
    {
    private var _glow:GlowFilter;
    private var _enableGlow:Boolean;

    private var _startDisplayObject:DisplayObject;
    private var _endDisplayObject:DisplayObject;

    private var _isTrackingMouseStart:Boolean;
    private var _isTrackingMouseEnd:Boolean;

    public function LightningPreset(enableGlow:Boolean = true)
    {
    super();

    startX = 0;
    startY = 0;
    endX = 200;
    endY = 200;

    this.enableGlow = enableGlow;

    addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
    }

    private function onAddedToStage(event:Event):void
    {
    stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);

    if (isTrackingMouse())
    {
    stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
    updatePositions();
    }
    }

    private function onRemovedFromStage(event:Event):void
    {
    stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMove);
    stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
    }

    private function onMove(event:MouseEvent):void
    {
    updatePositions();
    }

    private function onEnterFrame(event:Event):void
    {
    update();
    updatePositions();
    }

    public function setStart(object:*):void
    {
    if (stage)
    {
    stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMove);
    }
    _startDisplayObject = null;
    _isTrackingMouseStart = false;

    if (object)
    {
    if (object is Stage)
    {
    _isTrackingMouseStart = true;

    stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
    updatePositions();
    }
    else if (object is DisplayObject)
    {
    _startDisplayObject = object;
    }
    else if (object is Point)
    {
    startX = object.x;
    startY = object.y;
    }
    }
    }

    public function setEnd(object:*):void
    {
    if (stage)
    {
    stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMove);
    }
    _endDisplayObject = null;
    _isTrackingMouseEnd = false;

    if (object)
    {
    if (object is Stage)
    {
    _isTrackingMouseEnd = true;

    stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
    updatePositions();
    }
    else if (object is DisplayObject)
    {
    _endDisplayObject = object;
    }
    else if (object is Point)
    {
    endX = object.x;
    endY = object.y;
    }
    }
    }

    public function isTrackingMouse():Boolean
    {
    return _isTrackingMouseStart || _isTrackingMouseEnd;
    }

    private function updatePositions():void
    {
    if (_isTrackingMouseStart)
    {
    startX = mouseX;
    startY = mouseY;
    }
    else if (_startDisplayObject)
    {
    startX = _startDisplayObject.x;
    startY = _startDisplayObject.y;
    }

    if (_isTrackingMouseEnd)
    {
    endX = mouseX;
    endY = mouseY;
    }
    else if (_endDisplayObject)
    {
    endX = _endDisplayObject.x;
    endY = _endDisplayObject.y;
    }
    }

    ////////// GETTERS & SETTERS //////////

    public function get enableGlow():Boolean
    {
    return _enableGlow;
    }
    public function set enableGlow(value:Boolean):void
    {
    if (_enableGlow != value)
    {
    _enableGlow = value;

    if (value)
    {
    if ( !_glow)
    {
    _glow = new GlowFilter();
    _glow.color = 0xffff;
    _glow.strength = 4;
    _glow.quality = 3;
    _glow.blurX = glow.blurY = 10;
    }
    blendMode=BlendMode.ADD;
    filters = [_glow];
    }
    else
    {
    filters = null;
    }
    }
    }

    public function get glow():GlowFilter
    {
    return _glow;
    }
    public function set glow(value:GlowFilter):void
    {
    _glow = value;

    if (enableGlow)
    {
    filters = [_glow];
    }
    }
    }
    }

  69. Pierluigi Pesenti  •  Sep 11, 2011 @7:13 am

    nice addition, thank you.

  70. Sam  •  Sep 18, 2011 @7:42 pm
  71. cozzz  •  Oct 4, 2011 @10:03 pm

    ciao pier!

    great code and effect, really is awesome!

    im pretty new to as, im just trying to assign this class to a movie clip and im having trouble, i just need the lightning to show staticly on the stage from two points , any thoughts?

  72. romamik  •  Jan 11, 2012 @3:59 pm

    Hi.

    Great class!
    Can I use it in my game?

    Roman.

  73. Pierluigi Pesenti  •  Jan 11, 2012 @11:08 pm

    You can. Just send me a link to the game when it’s published. Yo.

  74. Dave  •  Jan 23, 2012 @11:24 pm

    Is the download still up to date? I’m not even that great at AS2, but I’m hoping to be able to incorporate this gorgeous lightning effect into a project I’m working on. Still trying to figure out AS3 and I can’t seem to get this thing working. Am I missing anything?

  75. Dave  •  Jan 25, 2012 @4:39 pm

    ….nevermind. I’m slowly figuring it out. Thank you so much for providing this code!

  76. OnurOrhan  •  Mar 20, 2012 @10:19 pm

    need to swf this application. please help me. mail address onur-orhn@hotmail.com

  77. cucsat  •  Apr 3, 2012 @8:47 am
  78. Miguel Angel  •  Apr 11, 2012 @5:27 am

    Hello Pierluigi and all of your fans !!!!

    I am from Spain. I am studying game designer, but I am still a newcomer in this.

    Thank you very much for this amazing cod. If you don’t ming, I’d like to use it in a proyect for the university. Of course, I would send it to you when I had finished it and I would mention you in the credit…….jajaja, I am a rookie and I almost don’t know anything about coding…

    Also thank to Gabriel because without his extension I think I wouldn’t have been able to use this amazing class.

    Chau.

  79. P48l0  •  Aug 20, 2013 @7:44 pm

    Awesome class!! seriously, very good looking lighting.

7 Trackbacks

Leave a Reply

Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>