Skip to main content

About the Layout Demo

Save Files There are two different types of save files: • CdemoSaveFile.txt: contains the GUID of the current TScene (the GUID in the left column of the TSceneList asset’s custom editor window). • CdemoSaveFile_guidstring.txt: contains JSON representing the data in the ChunkingDemoSavedData for a particular scene. The ‘guidstring’ is the GUID of the TScene that the data is for. When the demo starts for the very first time, there are no save files so the first scene in the TSceneList is loaded. When a waypoint is reached the scene’s data is saved, and the guidstring part of the filename is the same as the currently-loaded scene’s GUID. After that the CdemoSaveFile.txt does exist, and the GUID found there is used to load the corresponding TScene. Start The Start method does all the setup for the demo game. It first calls VerifySetup which validates some of the fields and caches a few references. After that it creates two RuntimeScriptableSingleton instances: one for game state (GameState SO) and one that’s a simple back end for save files. After waiting for TpLib to be ready, a callback is added to TpLib that tells us if a TilePlus tile is added or deleted. Why’s that important? Since this is a chunking system, we need to restore state to TilePlus tiles; e.g., if a waypoint has already been used, if a treasure chest has already been opened, etc. Examining the callback itself shows that added TilePlus tiles are tested to see if they support the persistence interface. If they do, the GameState SO provides the data which is restored to the specific tile using the persistence interface. The next important bit of code in Start is used to initialize the GameState SO. Some of the initialization is performed when TScenes are loaded using TSceneInitializers. Here we just set up a list of all the Tilemaps in the Unity scene. Next, we initialize the TpChunkedSceneManager component, whose reference was cached during validation (VerifySetup). First, the three important callbacks are set up: OnBeforeTSceneChange: called just after SceneManager.SetScene is called. This is used to clean up the current Unity scene, mask the camera during a scene change, or any other housekeeping required before a TScene change commences. OnNewTSceneChosen: The new scene was correctly chosen. In the demo this callback saves the GUID of the new TScene in the filesystem. That way the next time that the demo begins it will use that TScene as the starting TScene. OnAfterTSceneChange: The load is complete. All TSceneInitializers have run. Here one performs any final setup. For the demo this includes: Determining the location and GUID of the waypoint to use for placing the Player requires reading the save files. If found, the location and GUID of the current waypoint for the TScene are available. If not, the zeroth TScene from the TSceneList is used, and the single waypoint with the m_IsStartWaypoint field = true is used as the start position. Once we know where to place the Player, we create one if necessary and/or place it in the proper position. When creating a Player we also set up the Camera follower component (placed on the Camera GO). Finally, we update all the TpZoneLayout components, which will be discussed next. It’s important to note that while we know where the initial waypoint location is prior to updating the TpZoneLayouts, the actual TilePlus tile used for the waypoint is NOT actually on any Tilemap until after the TpZoneLayout updating is complete and the tiles are actually loaded. That’s the reason for this: if (startWaypointGuid != string.Empty) { var guid = new Guid(startWaypointGuid); while (!TpLib.HasGuid(guid)) { await Task.Yield(); } }

What’s happening here? Once the waypoint is loaded its GUID will appear in TpLib’s GUID list. This is very conservative and probably redundant but is a good practice if you want to absolutely ensure against a race condition. Finally, if a save file was located then use the JSON data from the save files to update loaded TilePlus tiles with the current state that they should be using.
Update Update in this demo is simple. It moves the Player based on what keys are pressed and calls UpdateLayout. UpdateLayout UpdateLayout checks to see if the Player has moved to a new Grid position. If not, there’s no need to re-layout the Tilemap chunks. Then for each TpZoneLayout which is currently in use a Task is created which invokes the TpZoneLayout’s UpdateTickAsync, which we’ll talk about next. Then we wait for all these tasks to be completed. Finally, UpdateTiles is called. That method messages the new position to all of the TilePlus tiles that want to know the new position. At this stage, TilePlus tiles that are messaged may post Save or Trigger events, which are handled by TpEventsOnTileEvent. If TpEventsOnTileEvent had set certain flag variables, they’re handled by HandleSaveEvent or HandleTriggerEvent. Waypoints Waypoints can just save game data and the current waypoint position, or it can do that AND change to a new TScene. That’s controlled by the m_IsLevelChange field in the tile. If that’s FALSE then a Save event is emitted when the Player encounters a waypoint. If that field is TRUE then a Trigger event is emitted instead. • SaveDataEvent: Save the TScene’s data (ChunkingDemoSavedData class is JSONized). • TriggerEvent: Save the TScene’s data and load a new TScene based on the waypoint’s m_NextLevelGuid field. HandleSaveEvent This updates the save data: if the Event was from a waypoint then we record the waypoint’s position and GUID in the ChunkingDemoSavedData instance, then disable all other waypoints in the TScene. Then the GUID of the scene is saved and the overall game data are saved. Note that game data are not saved until the Player encounters a waypoint. HandleTriggerEvent This is an example of customization that can’t be handled by a TSceneInitializer. It looks at trigger events as cached in the TpEvents static class instance. If the tile is a TreasureChest then the count of encountered treasure chests is incremented for UI display only. Note that in this demo, TreasureChest tiles clear their sprite when encountered. That state is saved in the save data file and restored when the TScene is loaded again. If the tile is a waypoint then all other waypoints are disabled and the game state is saved. Then the m_NextLevelGuid field is passed to the TpChunkedSceneManager instance’s SetSceneFromSceneNameOrGuid and a new TScene is loaded. TpZoneLayout.UpdateTickAsync UpdateTickAsync uses information from the method’s parameter list and from the TpZoneLayout’s serialized fields in order to determine what to unload and load. Unloading means removing Chunks of tiles and Loading means adding Chunks of tiles. Chunks can be any size from 4x4 and higher. Note that the Chunk Size is specified as a single integer and not a Vector2Int: this means that chunks are always square. Chunk Size can’t be less than 4 and must be an even number. Basically, the area in the Camera view area (plus padding) is examined for any empty Chunks using data about already-loaded chunks which are maintained in the TpZoneLayout’s spawned TpZoneManager. As the Camera moves around, new empty chunks will be encountered, and they’re loaded. Additionally, already-loaded chunks will pass out of the Camera view area (plus padding) and such chunks are deleted. It’s deceptively simple; most of the actual loading and unloading is performed in TileFabLib and the “Chunkifying” of TileBundles is performed in the TileBundle assets themselves.