Help needed with 2d platformer lights

Yeah. couple of notes (I dont really know the state of everything so please take these notes with limited value):

  • Beware physics gaps (I think you can fatten the collider detection a bit). I noticed many times I ‘slipped through’ the colliders and fell to my doom :slight_smile:
  • Not sure using string.format in get_key is a good idea - this is called alot. And it essentially generates a new string everytime. While not an issue atm, might be worth a simple refactor. (suggestion below)
  • The map Vs tile mask calc is a little tricky because I used a simple fixed square image for dumping the tilemap on. I tried using the WIDTH and HEIGHT but in the render tile section, I often got values outside that (which was weird - again, I might be misunderstanding a whole heap). Would recommend testing this a bit. It happened a couple of times where all the tiles changed too! Kinda freaked me out, I thought I had done something wrong, but I noticed your render tiles iterates a different table (viewport) than the tile pool being maintained. Not sure if this is a possible source of that (ie the two getting out of sync).

Otherwise its all very very cool what you have done. And actually, I love the premise. Has hints of the old Boulderdash (on C64) :slight_smile:

With regards to the key lookup. If you really want to use say a combo id for a tile X/Y pair you could use a little of bit ops fun :slight_smile:

Consider X and Y have a maximum size of a 16 bit value (65535). You could then simply combine them into an int. So the upper and lower portions of the int have the X+Y.
If you only use positive numbers. Its as simple as:
key = Y * 0xFFFF + X – this is same as Y * 65536 + X , I just like using HEX notation (old habits)
If you want to still use negative tile values, it still works, you just need to make sure the sign bit is set on each when you set them and then extract them. This can be done by using bit op library like so:

local cleanY = bit.lshift( bit.band(Y, 0xFFFF), 16)  -- cleans the value for use and shifts to top half of int.
local cleanX = bit.band(X, 0xFFFF)
local key = bit.bor( Y, X )  -- Merges the number into a single key. 

-- For extraction you do the reverse
local Xval = bit. band( key, 0xFFFF)  -- Fetches just the lower 16bits of the key
local Yval = bit.band( bit.rshift( key, 16 ), 0xFFFF ) -- Shifts the key 16 bits right then grabs it like X.

There are a bazillion other ways you can do this sort of thing too. Even just multiplying the Y by 1000 and adding the X. Then opposite to extract. Assuming your X and Y are less than 1000 :slight_smile:

Anyway. If you have any q’s. Happy to help.

1 Like

Thanks for the suggestion, will definitely be improving this. ive been having lots of fun learning game dev and Defold in general however there are still many aspects of which i am trying to grasp an understanding of. Sometimes i just do the first thing that comes to my head and not really sure if its the best way, but that is also why i love this community as everyone is very helpful. With that said…

I have spent quite a few hours yesterday looking at your solution (didnt even get a chance to understand the actual shader yet as i am still trying to understand how you create a mask, which i didnt even know was possible to do it this way!) and a few things that i might need some help understanding.

  • In the main file where TILE generation happens, you create a stream and for empty tiles you assign its index to 255. Now out of curiosity can we use anything other than a stream here? Asking because i am not familiar with using streams or buffers in general and its new territory for me and maybe perhaps i could use some documentation/tutorials where i can learn more about these?
  • Also in the main script you set coordinates for
msg.post("@render:", "update_light_mask", { lightmask_pos = {x=min_x, y = math.abs(min_y), size = TILE_SIZE}, lightmask_handle = tex.handle } )
  • Now i am a bit confused because this does not happen for every empty tile or does it?

  • In the render script we still render render_to_render_target(self.render_target_lights, function() however seems like if this texture was removed from the shader everything still working as expected, so i am curious if this is not needed or is there something i am missing?

  • I have yet to dig deeper into the quad shader itself to figure out why are the masks offset a bit, but first i need to learn all the GLSL functions…

Thank you again!