How do I connect and switch between mutliple tile maps?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By nightblade9

TL;DR: If I have multiple connected tile maps (eg. a map made of 4x4 tilemaps in a grid), how do I manage them and connect them?

I just went through the Using Tilemaps documentation. I can now create maps, and presumably should do so, using something like one scene per map.

However, it’s not clear to me how I should organize them. For example, as a visual editor, I expect that Godot should provide some easy/powerful way to view the entire 4x4 grid visually in some way so I can manage the “big picture” easily. But – assuming I don’t really want a giant map, and I want the player to traverse scene by scene – I don’t see how that’s possible.

The other thing that confuses me is how to transition from scene to scene. In other engines, I would probably have references (eg. a map ID) and change the content of the scene based on that. How do I handle that in Godot? I can instance a scene at runtime, but if I destroy the current scene, the player entity gets destroyed too.

:bust_in_silhouette: Reply From: picnic

You can set the value of any tile in a tile map (or 4!) using:

TileMap.set_cellv( Vector2 position, int tile, bool flip_x=false, bool flip_y=false, bool transpose=false )

The position supplied could be relative to your player or whatever so Tilemap 1 is your player position, Tilemap 2 is some offset from player position etc.

Do you actually need four separate tilemaps or four independent views of the same tilemap?

It might help to clarify the question a bit :smiley:

With regard to destroying a scene, you could make your ‘player’ scene the root and add or remove child scenes as required. Another alternative is to use Project Settings → Autoload to use a ‘singleton’ to store persistent data:

Sorry, I guess I didn’t describe my use-case / workflow clearly. Here are some diagrams that probably don’t do it justice.

The world map is a grid of 4x4 different screens/levels/areas/whatever, represented by a different-coloured square:

enter image description here

Each of those coloured squares is a separate, independent tilemap. What I want to know is: how can I set this up in Godot so that:

  1. I can see the “overall” world map of all the pieces connected to each other, and
  2. Assuming this is not just one giant map – the player sees one piece at a time – how do I technically pull that off?

My initial thought was to make each piece of the map a scene, and load/unload at runtime. But, if I do that, I don’t see how I can view the entire map in one shot somehow.

I’m not even sure it’s possible to do what I’m asking, to be honest.

nightblade9 | 2018-07-09 21:31

How do you have multiple tilemaps? Aren’t they essentially infinite?

duke_meister | 2018-07-09 22:05

I’m a noob so maybe I’m doing this wrong. I have a fixed map, nothing random or infinite. Am I supposed to create a single tile map, and then one scene per map. That’s my dilemma: how to switch the map to a new one when the player goes off screen.

If I was writing this without Godot, I would have maps defined as just data, like JSON or the Tiled editor format, and just load the new set of data when the map changes.

Maybe my core question should be “how do I create a world with multiple screens/maps and switch maps when they player moves off screen?”

nightblade9 | 2018-07-09 22:41

I understand the question (actually there are 2 questions), but as a beginner myself I’m also trying to understand tilemaps in Godot :slight_smile: Maybe you could have tilemaps on different layers and make these visible/invisible as needed.

duke_meister | 2018-07-09 22:43

I think I figured out a solution to this. I’ll test it out and post an answer if it works well enough for my taste.

nightblade9 | 2018-07-10 02:54

You only need one tilemap to achieve this - here’s one solution…

Create a 2d array representing the tiles of your entire world - call it world[comment5-] and say it’s 100x100 cells. Create a tilemap and copy values to it from world[0][comment5-0] to world[24][comment5-24]. Your tilemap will then be displaying the top left area (red square).

Now you want to show the player the adjacent yellow area… .clear() the tilemap and copy values from world[25][comment5-25] to world[49][comment5-49] to it. The player now sees the yellow area.

Now say you want to view the entire map (in game). Clear the tilemap, copy the entire world[comment5-] array into it and there it is (you might have to scale it or scroll it to view the entire thing).

An alternative might be to have a viewport you can move around to show the relevant area: Viewports — Godot Engine (3.0) documentation in English

Another alternative is to use the world[comment5-] array instead of a viewport, where each value in the array indicates a sprite to display although I think that would be poorer performance-wise.

picnic | 2018-07-10 06:49

:bust_in_silhouette: Reply From: nightblade9

I sorted this out myself. It’s not clear from any of the tutorial materials how to do this (I guess it’s left up to the game developers to figure out how they want to do it), so I went with a very simple approach:

  • Define your TileSet in one scene, export as a TileMap
  • Create a second, “master” scene (eg. Start.tscn/Start.gd) representing the current state of the game world
  • Create one scene per map, using your TileMap/TileSet
  • In this scene, call load("...") to load your scene-per-map for the current scene and store the variable
  • When switching scenes, call queue_free on the current instance if not null (to destroy the current scene) and load the next scene

The most important code (Start.gd):

extends Node2D

var current_map
var maps = {
	"meadow1": "res://Maps/Overworld/Meadow1.tscn",
	"meadow2": "res://Maps/Overworld/Meadow2.tscn",
	"meadow3": "res://Maps/Overworld/Meadow3.tscn",
	"meadow4": "res://Maps/Overworld/Meadow4.tscn"
}

const STARTING_MAP = "meadow1"

func _ready():
	self.show_map(STARTING_MAP)

func show_map(map_name):
	if self.current_map != null:
		self.current_map.queue_free()
		
	self.current_map = load(maps[map_name]).instance()
	self.current_map.z_index = -1 # draw under the player
	self.add_child(self.current_map)

This makes it easy to create scenes in isolation and link them up however I want. I can’t see the whole world-view at once, but I think that requirement is a bit crazy (for example, I’m not guaranteeing that my world is a rectangular grid).

Here’s a screen-shot of my work in progress (excuse the crappy place-holder graphics) showing two tilemaps in one scene using the method I outlined earlier.

The smaller tilemap (top left) shows an area of the world map (lower z). They’re not usually both visible - I have a key set to toggle between them ie make each visible or not as required. Each tilemap has its own tileset as you can see. The ‘generator’ node is instanced in my main scene.

Pasteboard - Uploaded Image

picnic | 2018-07-10 15:55