Lighting

by @Pattentrick

One of the many awesome things that Impact++ has to offer, are dynamic lights that can be used right out of the box. You can cast static shadows which are based upon your collision map and dynamic ones for moving entities. You can change the colour of your light to a specific value, modify it's opacity, and use a pixel perfect rendering for your cone of light. You could even cast shadows that are specific to certain entity animations! You don't know how to use all the cool stuff I just mentioned? Then this tutorial is for you. Let me enlighten you and shed some light on how this awesome feature of Impact++ works.

The Basics

Open a level with the Weltmeister level editor. Make sure that you are on the entities layer and hit space. A drop down should now be visible with your own entities and some that came with Impact++.

If you just see your own entities in that list, assure yourself that you copied the Impact++ config.js in your weltmeister folder. That file can be found in the Impact++ project folder under lib\weltmeister\config.js.

Select an entity called "Light" and drag it to your level. Looks a bit to small? You can easily scale it up in Weltmeister! Your light should now look like this:

lights1

You can change the colour of your light via it's RGB values. For example, like this you could make your light red:

r: 1
g: 0
b: 0

RGB values in Impact ++ are ranging from 0 to 1. In case you are wondering how you could express something like R: 198 with that notation, just divide your original value by 255. So R: 198 becomes 0.77.

It is also possible to change the colour of your light dynamically, if you add the following property to your light entity:

dynamicColor: true

As with every entity you can change the alpha property of it, to fit the atmosphere of your game better.

alpha: 0.6

Did you notice the gradient of the light? Don't like it? You can easily disable it like this:

gradient: false

Also you can render your light in a retro pixel perfect style. Just add this to your light entity:

pixelperfect: true

But remember, pixel perfect scaling has a very high performance cost, so use it wisely. As well make sure to disable the gradient, or else pixel perfect scaling won't work

Static Shadows

That light we made is looking very neat, but as you all know, where there is light, there must be shadow. So let's add some! First, add the following to your light entity:

castsShadows: true

Your light is now almost ready to do some cool shadow casting. But to cast shadows, based upon your collision map, you have to modify the shapesPasses property of your game. Append this code to your game class in your main.js:

// convert the collision map shapes
// either or both can be removed
shapesPasses: [
    // for climbing
    // we ignore solids and one ways
    // to only retrieve climbable areas
    {
        ignoreSolids: true,
        ignoreOneWays: true
    },
    // for lighting and shadows
    // we ignore climbables and the edge boundary
    {
        ignoreClimbable: true,
        // throw away the inner loop of the edge of the map
        discardBoundaryInner: true,
        // throw away the outer loop of the edge of the map
        retainBoundaryOuter: false
    }
]

Add some collision tiles and fancy graphics around your light. You should now see something like this:

lights2

Pretty cool, eh? Static shadows based upon our collision map! But maybe you have already noticed that something is wrong with the picture above. Where is the shadow of the pretty young girl?

Entities and Shadows

By default entities don't cast any shadows. But we can simply change this, by setting the opaque property of the entity which should cast shadows to true:

opaque: true

It is important to note that you should define opaque when you create that entity and not after. As Impact++ keeps a list of all opaque entities for performance reasons and this list changes only if an entity is removed or added to the game.

But shadows are calculated once per level, so even if you have an opaque entity nothing will happen unless you define the following on your light:

castsShadowsMovable: true

performance: movable

Also make sure that the entity which should cast shadows is dynamic:

performance: dynamic

Your entity should now cast some awesome looking shadow!

lights3

You can specify how much light will be blocked by opaque entities. Set the diffuse property to any value you like from 0 to 1:

diffuse: 0.4

Keep in mind that pixel perfect light has a very high performance cost, so you should avoid casting shadows on moving entities with your pixel perfect light. You will not get more than 2 � 5 FPS at best.

Animation Specific Shadows

On top of that you can enable animation specific shadow casting. This can be easily achieved by modifying the animSettings of your entity class:

jumpX: {
    sequence: [16, 18, 19],
    frameTime: 0.05,
    // animation specific shadow casting!
    // i.e. when playing this animation
    // shadows will be cast using the base size
    // with these offsets
    // (also used in other animations)
    opaqueOffset: {
        left: 6,
        right: -6,
        top: 0,
        bottom: -5
    }
}

On your entity class you can also add a, non animation specific, general shadow casting setting:

// general shadow casting
// i.e. when playing any animation
// shadows will be cast using the base size
// with these offsets

opaqueOffset: {
    left: 6,
    right: -6,
    top: -1,
    bottom: 3
}

Learn More!

Light Entity
shapesPasses property
Config file