---
title: "cocos2d-x dynamic light tutorial"
description: "Tutorial: Create amazing 2d light effects for your Cocos2d-X game using normal mapped sprites."
canonical: "https://www.codeandweb.com/spriteilluminator/tutorials/lighting-demo-cocos2d-x"
date: "2015-05-12T00:00:00.000Z"
modified: "2015-05-12T00:00:00.000Z"
source: "html"
---

# cocos2d-x dynamic light tutorial

Joachim Grill

[spriteilluminator](https://www.codeandweb.com/tags/spriteilluminator),  [cocos2d-x](https://www.codeandweb.com/tutorials/cocos2d-x.md),  [tutorial](https://www.codeandweb.com/tags/tutorial)

[GitHub](https://github.com/CodeAndWeb/cocos2d-x-dynamic-lighting)

![cocos2d-x dynamic light tutorial](https://www.codeandweb.com/static/ae6fbeeeb6121361234073d61b942555/a6312/post-image.png)

What you are going to learn:

*   Create your normal maps + sprite sheets using [SpriteIlluminator](https://www.codeandweb.com/spriteilluminator.md) and [TexturePacker](https://www.codeandweb.com/texturepacker.md).
*   Load animation frames from a sprite sheet
*   Load a normal map sprite sheet and add a light effect to your animation

Video: **Gamescene with 2d light effects using normal maps** (0:15) https://player.vimeo.com/video/128353876?h=84f7027957

#### What you are going to learn

*   Create your normal maps + sprite sheets using [SpriteIlluminator](https://www.codeandweb.com/spriteilluminator.md) and [TexturePacker](https://www.codeandweb.com/texturepacker.md).
*   Load animation frames from a sprite sheet
*   Load a normal map sprite sheet and add a light effect to your animation

### Create your normal maps

The easiest way to create normal maps for your sprites is to use [SpriteIlluminator](https://www.codeandweb.com/spriteilluminator.md). For a quick start you simply

*   Drag + drop your sprites on the SpriteIlluminator window
    
*   Select all sprites
    
*   Apply **Bevel** and **Emboss** effects
    
*   Publish the normal map images to the sprite directory, using the `_n` suffix
    

### Create the sprite sheets

With [TexturePacker](https://www.codeandweb.com/texturepacker.md) you can pack sprites + normal maps on two different sprite sheets, using the same layout:

*   Start TexturePacker and create a new **cocos2d** project
    
*   Drag + drop sprites and normal maps on the TexturePacker window
    
*   Enable the **Pack with same layout** option in the **Normal Maps** section
    
*   Publish the sprite sheets
    

### Setup your Cococ2D-x project

To create a new Cocos2d-x project we can use the `cocos` command, with the option `-l cpp` we create a C++ "hello world" project.

```bash
~/Frameworks/cocos2d-x $ cocos new LightingDemo -l cpp
```

```
Running command: new
> Copy template into /Users/joachim/Frameworks/cocos2d-x/LightingDemo
> Copying cocos2d-x files...
> Rename project name from 'HelloCpp' to 'LightingDemo'
> Replace the project name from 'HelloCpp' to 'LightingDemo'
> Replace the project package name from 'org.cocos2dx.hellocpp' to 'org.cocos2dx.LightingDemo'
> Replace the mac bundle id from 'org.cocos2dx.hellocpp' to 'org.cocos2dx.LightingDemo'
> Replace the ios bundle id from 'org.cocos2dx.hellocpp' to 'org.cocos2dx.LightingDemo'
~/Frameworks/cocos2d-x $
```

Open the new project using Xcode or VisualStudio.

### Load sprite sheet and add an animation

We can replace the `init()` method of HelloWorldScene.cpp by our own: First we have to load the sprite sheet data file (the one with the .plist extension) into the `SpriteFrameCache` . The texture image file is automatically loaded, its name is composed by replacing the .plist suffix with .png:

```cpp
bool HelloWorld::init()
{
    if (!Layer::init())
        return false;

    auto spritecache = SpriteFrameCache::getInstance();
    spritecache->addSpriteFramesWithFile("spritesheet.plist");
```

Now we can fetch the individual sprite frames of our animation from the cache:

```cpp
    Vector<SpriteFrame*> animFrames;
    char str[100];
    for(int i = 1; i <= 8; i++)
    {
        sprintf(str, "character/%02d.png", i);
        animFrames.pushBack(spritecache->getSpriteFrameByName(str));
    }
```

Finally we create a sprite, set the `Animate` action on it, and add the sprite to the scene:

```cpp
    auto sprite = Sprite::createWithSpriteFrame(animFrames.front());

    Animation *animation = Animation::createWithSpriteFrames(animFrames, 1.0f/8);
    sprite->runAction(RepeatForever::create(Animate::create(animation)));
    sprite->setPosition(Director::getInstance()->getWinSize() / 2);

    addChild(sprite);

    return true;
}
```

If you start the demo application, the (still unlit) animation is played in the center of the screen.

  ![Simple sprite sheet animation in cocos2d-x](https://www.codeandweb.com/static/f93a13a24c654253cdda90ba50eb9e58/0d81c/cocos2d-x-sprite-sheet-animation-2.jpg)

### Creating a point light effect using a fragment shader

The brightness of each sprite pixel depends on the angle between the light vector and the normal vector (stored in the normal map). This calculation is done by an OpenGL fragment shader:

*   [PointLight.frag](https://github.com/CodeAndWeb/cocos2d-x-dynamic-lighting/blob/master/LightingDemo/Resources/pointlight.frag) contains the shader code for a point light
    
*   [LightEffect](https://github.com/CodeAndWeb/cocos2d-x-dynamic-lighting/blob/master/LightingDemo/Classes/EffectSprite/LightEffect.h) is a class which sets some uniforms (global OpenGL variables) on the shader
    
*   [Effect](https://github.com/CodeAndWeb/cocos2d-x-dynamic-lighting/blob/master/LightingDemo/Classes/EffectSprite/Effect.h) is a base class for `LightEffect`
    
*   [SpriteEffect](https://github.com/CodeAndWeb/cocos2d-x-dynamic-lighting/blob/master/LightingDemo/Classes/EffectSprite/EffectSprite.h) is derived from `Sprite` , it provides a method to set an `Effect` on the sprite
    

You can clone all sources from [GitHub](https://github.com/CodeAndWeb/cocos2d-x-dynamic-lighting).

### Adding the light effect to the Sprite

First of all you have to modify the code from above, as we want to use an `EffectSprite` instead of a `Sprite` :

```cpp
auto sprite = EffectSprite::createWithSpriteFrame(animFrames.front());
```

Now we create an instance of the `LightEffect` and configure some properties.

```cpp
    _effect = LightEffect::create();
    _effect->retain();

    Vec3 lightPos(200, 200, 100);
    _effect->setLightPos(lightPos);
    _effect->setLightCutoffRadius(1000);
    _effect->setBrightness(2.0);
```

The `LightEffect` creates a point light. A point light is a light source that emits light from a single spot in all directions. Think of it as a candle, torch, light bulb.

The effect class lets you set several parameters for the effect:

*   **`setLightPos`**  
    The position of the light in the scene. The light source can be placed in 3 dimensions. That means that you can place it between the player and the screen — to light the scene. The z-position can dramatically change the effect you get from the light effect.
*   **`setLightColor`**  
    Sets the color of the light source
*   **`setBrightness`**  
    Sets the brightness of the light: with a value of 1.0 and a white light color a rendered pixel will never get brighter than its original value in the texture. With brightness values >1 the pixels can get overexposed.
*   **`setLightCutoffRadius`**  
    The radius at which the light source does not have any effect on the sprite.
*   **`setLightHalfRadius`**  
    The radius at which the light's intensity decreases to 50%. The value range is \[0 … 1\], relative to the cut-off radius. A value of 0.5 will give you a soft light, a value of 1 a light with hard edges.
*   **`setAmbientLightColor`**  
    Sets the color of the background light. This is a non-directional light which lights the sprite from all sides.

  ![Diagram showing light cut-off radius and half radius parameters for lighting effects](https://www.codeandweb.com/static/ff1f201aeed569252c331558df63c530/35811/light-cut-off.jpg)

The newly created `LightEffect` can be set on the `EffectSprite` . The sprite sheet with the `_n` suffix contains the normal maps for all sprites. It is important that this sheet is packed with the same layout as the sprites!

```cpp
sprite->setEffect(_effect, "spritesheet_n.png");
```

After adding these few lines our application displays a lit animation, but we are not yet able to move the light position. We are going to change this in the next section.

  ![Adding a light effect to the cocos2d-x animation](https://www.codeandweb.com/static/278fa218bfde1a38ad1a216481547353/0d81c/cocos2d-x-sprite-sheet-animation-with-light-2.jpg)

### Adding a light bulb

Let's add a sprite symbolizing the light source:

```cpp
    _lightSprite = Sprite::create("lightbulb.png");
    _lightSprite->setPosition(lightPos.x, lightPos.y);
    this->addChild(_lightSprite);
```

To allow the user to move around the light bulb we register some touch callbacks:

```cpp
    auto listerner = EventListenerTouchAllAtOnce::create();
    listerner->onTouchesBegan = CC_CALLBACK_2(HelloWorld::handleTouches, this);
    listerner->onTouchesMoved = CC_CALLBACK_2(HelloWorld::handleTouches, this);
    listerner->onTouchesEnded = CC_CALLBACK_2(HelloWorld::handleTouches, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listerner, this);
```

The implementation of `handleTouches()` is quite simple, we update the position of the light bulb sprite, and tell the effect where our light is positioned now:

```cpp
void HelloWorld::handleTouches(const std::vector<Touch *> &touches, cocos2d::Event *)
{
    for (auto &touch: touches)
    {
        Point pos = touch->getLocation();
        _lightSprite->setPosition(pos);
        _lightPos.set(pos.x, pos.y, _lightPos.z);

        _effect->setLightPos(_lightPos);
    }
}
```

In the demo project on [GitHub](https://github.com/CodeAndWeb/cocos2d-x-dynamic-lighting) we've also added some background images:

  ![Simple sprite sheet animation in cocos2d-x](https://www.codeandweb.com/static/bc8a39cbc8b3036137c64f95cd8d4040/0d81c/cocos2d-x-sprite-sheet-animation-with-movable-light-2.jpg)

## Structured data

```json
{
  "@context": "https://schema.org",
  "@type": "TechArticle",
  "headline": "cocos2d-x dynamic light tutorial",
  "author": [
    {
      "@type": "Person",
      "name": "Joachim Grill"
    }
  ],
  "dateModified": "2015-05-12T00:00:00.000Z",
  "image": "/static/ae6fbeeeb6121361234073d61b942555/a6312/post-image.png"
}
```

```json
{
  "@context": "https://schema.org",
  "@type": "VideoObject",
  "thumbnailUrl": "https://i.vimeocdn.com/video/519452598-810646067032f928b00274c541b2a47e276cfd206df40ac379c9468fae237fa7-d?f=webp",
  "embedUrl": "https://player.vimeo.com/video/128353876?h=84f7027957",
  "name": "Gamescene with 2d light effects using normal maps",
  "description": "2d game scene with dynamic light effects.   For this scene, we used SpriteIlluminator to create the normal maps.  https://www.codeandweb.com/spriteilluminator",
  "height": 1080,
  "width": 1920,
  "videoQuality": "HD",
  "uploadDate": "2015-05-20T05:33:15-04:00",
  "dateModified": "2024-06-25T06:05:06-04:00",
  "duration": "PT00H00M15S",
  "keywords": [
    "2d dynamic light",
    "normal map",
    "2d game",
    "unity",
    "cocos2dx",
    "cocos2d"
  ],
  "thumbnail": {
    "@type": "ImageObject",
    "url": "https://i.vimeocdn.com/video/519452598-810646067032f928b00274c541b2a47e276cfd206df40ac379c9468fae237fa7-d?f=webp",
    "width": 1280,
    "height": 720
  },
  "url": "https://www.codeandweb.com/spriteilluminator/tutorials/lighting-demo-cocos2d-x"
}
```
