Oh, that sounds like exactly what I need! I will try that, thank you! Will it still work with TileMapLayers?

Edit:
Sorry for being a bit thick, but how can I copy tiles between tilemaps?

  • xyz replied to this.

    Tomkun No reason not to work. You'll just have to maintain two sets of layers.

      xyz
      Thanks so much for your idea. I have all the raycasting code working now, but am still unsure of how to copy the discovered tiles to the new TileMapLayer. I can only find commands to copy the entire layer.

      • xyz replied to this.

        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.