Dynamic Lighting

by Forum_account
Dynamic Lighting
An easy way to add dynamic lighting to your game.
ID:119719
 
Keywords: dynamiclighting
To some extent I hate the idea of dynamic lighting implemented as a library in DM. Dynamic lighting should be handled primarily on the client. The developer writes some code that marks objects as being light sources, the server tells the client about the light sources, and the client renders the shading accordingly. To implement this as a library you need to create objects that graphically show the shading and update them all, then send the updates about the icon_state changes to clients to have them update how the shading looks.

I said that I hate this idea to some extent because I don't hate it enough to not implement it. I've posted the first version of a dynamic lighting library.

There are plenty of features that could be added. This is just the first version. I'm trying to provide basic functionality and keep it as simple as possible. To make a mob be a light source you just need to do this:

mob
Login()
..()
src.light = new(src, 3)


And later on you can modify the light by calling the light object's on(), off(), toggle(), or radius() procs.
Why are you so awesome? Why!?!?
I'm glad you like it, but we'll have to wait and see how many people actually use it in games =)
Is it just me or do you ever just wish there was a proc setting that allowed you to pass all work to the client?

like set client_handling=1 . The devs say that they can't include client sided handling because it'll mess with the timing that the coders make in their games. The thing is though, if a bit of code that you have is something that you want to offload to the client and that you CAN offload to the client, there's currently no way to do it. Maybe I should put in a feature request? OR at least I would, but I don't think I'm high profile enough to get noticed.
Being able to execute code on the client would be nice, but I'm not sure it'd help in this case. The lighting would still rely on having pre-rendered icon states representing each possible illumination state. A built-in solution could easily render the shading in a non-tile-based manner.

As for general code executing on the client - there are definitely problems and I'm not sure how difficult they'd be to work around. There are some decisions that would have to be made and it would be limited, so I'm not sure how useful it would end up being. It'd be limited because you can't do things like "for(var/mob/m in world)" and run it on the client because each client isn't aware of every mob.

I think it'd be useful for the client to be able to run code that changes properties of atoms as they're represented on the client. These changes would be local only - they wouldn't be propagated back to the server.

For example, suppose you create a dust cloud object and want it to slowly move by updating its pixel_x and pixel_y vars. Currently the server has to send updates to each client when the object is created and each time it moves. By executing code on the client you could have the server send a single message that tells the client there's a new dust cloud object and the clients figure out how to move it.

This would let developers make more elaborate visual effects without impacting the server. It would be just as complex (possibly less complex) than creating an object, flicking an animation, and deleting the object. You could have the client move and modify the object in a variety of ways and the network usage would be the same. This would greatly benefit from features like these two.
touché
I was trying to get the library in shape to add shadows. There isn't much that has to change (mostly just the atom/light() proc, if you'd like to take a stab at it). There are still some internal things that'd need to change because light sources currently update when they move, but with shadows you'd need to update light sources when a nearby, non-light-source moves too.
IIRC, Shadowdarke's DAL has wonky behavior with moving opaque objects. Admittedly, there aren't many situations for opaque objects to be moving. My system doesn't really have any support for opaque objects to move, but there is a function for setting opacity with the lightsource updates in mind.

Didn't you call me out for using an "incorrect" lighting system when I implemented shadows?

Not stopping me from implementing the shadowcasting algorithm in yours to do some speed tests.


[EDIT]: As it is right now, the difference yours vs mine in speed is something like a factor of 10 with the same radius inputs. Not to mention there's a lot of room for improvement as far as your system's speed goes.

I'm not a computer scientist so I'm not going to crunch out a function for operations per n calls.

Forum_account's lighting:
0.000018 seconds per call (euclidian distance)

Darke's lighting:
0.000273 seconds per call (shadowcasting)
0.000029 seconds per call (no shadows)
Now that I think about it, having opaque objects move is fairly complicated. You'd have to undo the lighting effects as they existed prior to the opaque object's move, then recalculate them after the move. It's possible but it probably wouldn't be very elegant.

Shadows are what'll slow it down, so I'd be curious to see how it performs then. I might try it later, but if you try it first let me know how it goes.
It's too bad you can't just set the brick wall's opacity to 1 and expect it to block light without a problem :(
Nice work as always :). One annoying limitation is that lighting seems to transform before the mob finishes moving tiles, as opposed to a smooth transition.
Kaiochao wrote:
It's too bad you can't just set the brick wall's opacity to 1 and expect it to block light without a problem :(

I had to leave some features for version 2.
Forum_account's lighting:
0.000018 seconds per call (no shadows, linear dropoff)
0.001400 seconds per call (darke shadowcasting, quadratic dropoff)

Darke's lighting:
0.000029 seconds per call (no shadows, quadratic dropoff)
0.000273 seconds per call (darke shadowcasting, quadratic dropoff)

I'll keep you updated as I work on it. Since my approach isn't working very well, you might get better results if you implement shadowcasting your own way (or if you use a different algorithm)
Neat library, nice job Forum!
More and more it feels like my game is based on nothing but your libraries..

When I first played around with your pixel-movement library, the isometric-demo inspired the current game I'm working on now. Not just the pixel movement but the jumping too. The game I am working on is about assassination, infiltration, and sabotage with an amazing historic background powering it.

The pixel movement, along with the ability to jump over walls that your library provided was essential to such a game.

I tried to comprehend how D4RK3 54B3R's lighting worked in his DarkeNyctoSource for the purpose of understanding how to go about making a lighting system of my own.. but knowing so little as I do about coding, I couldn't understand a thing hardly. To make matters worse, I have a hard time reading code as it is without #define u #define and u this asthis.. and what's with putting everything in a single line anyway? I'm sure he did it on purpose to confuse beginners >.<

As with most espionage games, things like jumping/climbing over objects and clever use of darkness are essential.

The lighting system in D4RK3 54B3R's d4_ASE is really amazing. I would like to see you continue to update this library in hopes that it is close in power to D4RK3 54B3R's lighting system but keeps its simplicity.

And compatability with isometric games would be nice too :D
Dragonsleeve wrote:
I tried to comprehend how D4RK3 54B3R's lighting worked in his DarkeNyctoSource for the purpose of understanding how to go about making a lighting system of my own.. but knowing so little as I do about coding, I couldn't understand a thing hardly. To make matters worse, I have a hard time reading code as it is without #define u #define and u this asthis.. and what's with putting everything in a single line anyway? I'm sure he did it on purpose to confuse beginners >.<

No, that source was compressed to qualify for the Cartridge Classic II contest. I just released it without decompressing it (I lost my normal copy...). Not to mention, that version of the lighting system had the shadowcasting removed for the sake of code size and compression to qualify for the contest.


The lighting system in D4RK3 54B3R's d4_ASE is really amazing. I would like to see you continue to update this library in hopes that it is close in power to D4RK3 54B3R's lighting system but keeps its simplicity.

My lighting system isn't necessarily better than his. Most of my lighting system was hacked together and because of my approach, my implementation is inherently more complex and thus slower (an example being vertex oriented).
Forum_account's setup is significantly simpler and more robust than mine. It would not take much work to get it casting shadows and doing the things my library can do that his cant.

And compatability with isometric games would be nice too :D

My library is compatible with isometric games. (Flame Sage's "Pressure")

I'm sure Forum_account's could be too, if he modified his icon generator a little (Since that's all I did to mine to make it work for isometric)
I posted an update which has some drastic changes to the internals. Some of the changes were made to improve how the library runs and how it can be used, but mostly the changes were made to accommodate the addition of shadows.

Shadows are implemented entirely in the demo (a new demo called "shadows-demo" was added) by overriding the atom/light() proc and the built-in Move() proc. Aside from overriding those procs, to use shadows you just have to set the "opaque" var (which the demo defines for all atoms) on the objects you want to cast shadows. Defining light sources still works the same way.

Dragonsleeve wrote:
And compatability with isometric games would be nice too :D

I'm not sure how well it'd look on isometric maps, especially if you have jumping and elevation. The illusion of shading works best with a top-down view because the display is strictly 2D - each point on the screen represents a single position. With an isometric display with 3D movement the player can be in multiple positions that map to the same location on the screen.

For example, you can get to the same position on the screen by standing in one place, or by moving downwards from that position and jumping. When you jump you move into the same position on the screen you were previously in - your x and y are different but your pixel_z puts you in the same spot.

What this means for lighting is that the same shadow object is drawn over top of the player and may not look correct. The shading is based on what the illumination on the ground looks like, so when you jump the incorrect illumination will be shown on the player.

The simple way of applying this to isometric maps might not work to well, but I can try it if you'd like to see how it looks.
I just posted another update which makes a minor change that makes it easier to customize. The world.illumination() proc and the atom.light() procs are replaced by light_source.lum() and light_source.effect().

light_source.lum(atom/a) - computes the amount of illumination the light_source object contributes to the specified atom. You can override this to change the illumination function to create different effects:

* Make it return a constant value of 5 to make it illuminate its radius fully.
* Make lights attenuate faster as distance increases
* Make illumination based on get_dist(src, a) so the light illuminates a square area
* Make it check what direction the atom is in and illuminate accordingly to create directional lights

There are examples of the last two included in a new demo called "customization-demo".

light_source.effect() - identifies the range of tiles affected by the light source and how much illumination is given to each tile. You can override this to change what tiles are considered for illumination. By default, all tiles in range(radius, src) are considered and lum() is called for each, but the effect only counts if lum() returns a value greater than zero.

* Make it do some visibility calculations to determine if a tile can be seen by the light source before it calls lum(). Tiles that cannot be seen are not illuminated, causing shadows.

There is an example of this in the "shadows-demo" demo.
I noticed something that acts a little odd. When making a movement the light moves instantly and then the movement is executed. Not sure how feasible it is, but could the light slide along with the player? Or possibly have the light fade in when affecting new turfs and fade out when leaving turfs?
Unfortunately, I don't think that either is feasible.

With 4 shades of brightness/darkness there are 4*4*4*4 = 256 icon states needed for the lighting. To create animated transitions between each pair of possible states would take quite a lot.

Having the light move with the player would be difficult to pull of, and even then it'd be problematic because you could have multiple moving light sources.

If you're using dynamic lighting with tile-based movement you might be able to delay the lighting update so it occurs during the movement, instead of occurring the instant the movement starts.

My hope is that the BYOND staff implements dynamic lighting so the method used by this library will be obsolete.
Page: 1 2