xyz
Thanks so much! I will check that out and let you know how I get on! I have a lot to think about!

I am really going around in circles with this. Would someone be kind enough to give me some pseudo-code about how this might look?

I have a main scene with two TileMapLayers called "HiddenFloorLayer" and "RevealedFloorLayer".
HiddenFloorLayer has the complete level layout, but is hidden.
RevealedFloorLayer has visible but empty.

I have a "Hero" who projects a raycast in front of him and sends the coords to the _update_tile function in RevealedFloorLayer.

In RevealedFloorLayer, I have the functions:

_update_tile(coords)

_use_tile_data_runtime_update(coords: Vector2i)

_tile_data_runtime_update(coords: Vector2i, tile_data: TileData)

I use the _update_tile() function to sort whether the tile needs to be updated and pulls the tiledata from it. So far, so good. I can output the data to the terminal, so I know it's working.

However, from there I don't understand how to use the other functions to copy the tiledata to the RevealedFloorLayer... All the examples I've seen online, for example here: Can’t get the _tile_data_runtime_update() function to work never seem to pass any data to the functions so I can't figure out how to do it?

Sorry if I'm being thick, but I feel like I'm this close....

  • xyz replied to this.

    Tomkun Maintain a list of tile coords that need to get visible. In _use_tile_data_runtime_update() check if the passed coord is in that list. If yes pop it from the list and return true. Otherwise return false.
    In _tile_data_runtime_update() use the coords you get to get the data from hidden layer and set that data to received TileData object.

      xyz
      Wow, that was fast!
      Here's what I have so far:

      extends TileMapLayer
      @onready var hiddenfloorlayer: TileMapLayer = $"../HiddenFloors"
      
      func _reveal_tile(collision_point: Vector2i):
      	var tile_pos = hiddenfloorlayer.local_to_map(collision_point)
      	var tile_id = hiddenfloorlayer.get_cell_source_id(tile_pos)
      	var tile_data = hiddenfloorlayer.get_cell_tile_data(tile_pos)
      	if tile_data:
      		_use_tile_data_runtime_update(tile_pos)
      		_tile_data_runtime_update(tile_pos,tile_data)
      
      func _use_tile_data_runtime_update(coords: Vector2i) -> bool:
      	if coords:
      		return true
      	else:
      		return false
      	
      func _tile_data_runtime_update(coords: Vector2i, tile_data: TileData) -> void:  
      	print(coords)

      At the moment it's just printing the coords out, but is that on the right lines?

      • xyz replied to this.

        Tomkun _use_tile_data_runtime_update() and _tile_data_runtime_update() are callbacks that the engine calls. Like _process() or _input(). You just need to implement them. They're not supposed to be called by your code. You may not even need those here. Try doing just set_cell() from _reveal_tile()

          xyz

          Okay, I'll try that.
          How can setcell() copy one cell to another tilemaplayer though?
          Never mind, I found out how. There isn't a direct copy it seems but you can extract all the info you need for setcell() with different functions and use them.
          However, unfortunately it seems like I am out of luck here.
          I am using BetterTerrain to place my tiles and I can't seem to reproduce them faithfully as their rotation and mirroring are randomised and I can't find a way to duplicate that.

          Thank you for all your help though. I have learned a lot!

          • xyz replied to this.

            Tomkun How about this instead. Make the full version of the map completely visible. Put an additional tile map layer over that. Fill this layer with full square tiles in a background color, effectively masking what's underneath. As you progress, just delete those mask cells for the cells in the map that have been revealed.

              xyz
              Yes, that would work but I have a background texture.
              Basically, my dungeon is supposed to look like it was sketched on paper, so there is a background paper texture.
              If I could duplicate that on the top layer and make sections transparent, that could work but I'm not sure if that's possible to do.

              • xyz replied to this.

                Tomkun Tile map layer is a canvas item. You can use it as an alpha mask.

                  xyz That sounds like the solution then. I will have a look into it. Thank you so much for all your help, pointers and suggestions!

                  xyz
                  Do the tiles act as the mask in this case? If I create a white tile, will that area become transparent?
                  Edit:
                  I've just answered my own question here, but no, this is not how it works. Tiles just act like tiles unfortunately.
                  How can I create a cell that is a mask?

                  • xyz replied to this.

                    Tomkun Hm, apparently the common canvas item children clipping doesn't work with tilemaps. You can render it into a separate viewport and use that viewport texture as an alpha mask. Alternatively you can slap your background texture over the tilemap by using a simple custom shader that draws the texture.

                    I think custom shaders are going to be a little advanced for me. I'm struggling as is. I will give the viewport idea a go.

                    • xyz replied to this.

                      Tomkun But wait. There's a simple way still using _tile_data_runtime_update() with just the original map. Maintain a list of invisible cell coordinates. Return true from _use_tile_data_runtime_update() if received coord is in that list. In _tile_data_runtime_update() simply set tile_data.modulate.a to 0.

                      Tomkun Example:

                      extends TileMapLayer
                      
                      var invisibles: Array[Vector2i]
                      
                      func _ready():
                      	for i in 5:
                      		invisibles.push_back(Vector2i(i,i))
                      
                      func _use_tile_data_runtime_update(coords):
                      	return coords in invisibles
                      	
                      func _tile_data_runtime_update(coords, tile_data):
                      	tile_data.modulate.a = 0

                      With this you can even animate fading in of the tiles as they become visible.

                        xyz
                        Wow, that sounds perfect!
                        It's going to take me a while to get my head around it. I don't really get the virtual functions yet. How are they called?

                        • xyz replied to this.

                          Tomkun The engine calls them. You just provide the code and the return value. Same as _process() which engine calls each frame. "Virtual" here only means that the function body is optional to implement by the user.

                          Whenever the engine is about to draw a cell, it will call your _use_tile_data_runtime_update and if it gets true as the return value, it will call your _tile_data_runtime_update() passing it a reference to that cell's tile data. You can alter that data and that's what it will be used for drawing the cell.

                          It's done like this so that updating is kept efficient i.e. it's only done for cells that really need it.

                          Okay, I think I get it.
                          So tile_data.modulate.a = 0 will make the cell invisible and I assume tile_data.modulate.a = 1 or 255 will make it visible again?

                          • xyz replied to this.

                            Tomkun And tile_data.modulate.a = .5 will make it half-transparent πŸ˜‰
                            But you don't need to ever set it to 1. You just need to keep the list of invisible cells up to date, and call notify_runtime_tile_data_update() whenever this list is changed.

                              xyz
                              Oh, I see, so if the tile is removed from the list, then it will become visible automatically?
                              No, that's not working... The tiles are being removed from the list but aren't becoming visible again.
                              Forget it, I was being dumb again.

                              Great news!
                              Thanks to you, it's working (kind of)! I still need to iron out some kinks in my raycasting I think, but tiles are appearing now!

                              • xyz replied to this.