Lightning with Sprite Kit

Have you ever tried to implement such effect as lightning for your iOS game? In this article I’m going to describe three ways I found to create a lightning effect with a decent quality:

  • SKShapeNode.
  • CAShapeLayer.
  • SKSpriteNodes.

For each of them we need to compose a path for our lightning bolt. I searched the web and found this article about procedural generation of lightning bolt. This approach uses Midpoint Displacement algorithm. The result looks pretty realistic. Here is Objective-C code for Midpoint Displacement algorithm:

Ok, we got the path, how about drawing it? “We can define SKShapeNode with our path!” — that’s how I thought.

SKShapeNode.

Let’s create SKShapeNode with UIBezierPath, created from our pathArray:

Defining SKShapeNode with UIBezierPath seems very simple, and result looks nice and realistic, but if you use a lot of such nodes, FPS dramatically drops. That didn’t suit me, so I came to the second approach: using CAShapeLayer.

CAShapeLayer.

CAShapeLayer allows us to draw a path on our view’s CALayer. Moreover, it offers a shadow setting for the path out of the box: by using shadowColor, shadowOffset, shadowRadius and shadowOpacity properties. Ok, let’s try that!

Using CAShapeLayer seems much more efficient than SKShapeNode:

But there are several cons:

  • The shadow looks very pale and unnatural
  • You cannot change zPosition of shapeLayer on SKScene. Thus you cannot place any of your SKNodes above shapeLayer.

I googled about other methods of lightning generation and found a great article “How to Generate Shockingly Good 2D Lightning Effects” by Michael Hoffman. He has written his project using C# and XNA, so I decided to make the same trick with using Objective-C and Sprite Kit’s SKSpriteNode!

SKSpriteNode.

First, we need to draw our building blocks: a half-circle image and a lightning segment. Here is what I got so far:

Second, Michael uses his own method to generate a lightning bolt path, but Midpoint Displacement algorithm seems more realistic for me, so I decided to keep using it. We don’t need UIBezierPath with this approach, so let’s slightly change the code of createBolt function:

Third, let’s create a special SKNode called LightningLine, which represents one single line of our path:

loadSharedAssets method loads our images to static variables, so it must be called before we initialize a node. The best way to call it is SKScene’s init method.

Finally, here is a method, that does all magic:

I prepared sample Xcode project, which includes all of the approaches described here: https://github.com/andrew8712/SpriteKitLightning

Here is Swift version: https://github.com/andrew8712/SpriteKitLightning-Swift

You can use it however you want to.

--

--

iOS/Android developer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store