Skip to main content
  1. Posts/

Day 30 - Intermap Navigation

OldDays ste-reez-muvi Unity csharp SQL

Finally switching between maps on the fly.

Apologies
#

Busy yet efficient.
Busy yet efficient.

Sorry for the long delay between posts; epic week at work.


Coding
#

Beyond map 3
#

In the table that stores the Cell data for a map, I had foolishly included the landID field (it indicates whether a given map belongs to the Beginners’ Game, Advanced Game, or Underworld) which is always the same for a given mapID. Hard-coding landID to zero just gave me the first four maps, so I modified the query in the stored procedure to ignore the field entirely.

DragonsSpine/SQL Scripts/prApp_LiveCell_By_MapID.sql
19
20
21
22
23
24
25
26
27
CREATE PROCEDURE [dbo].[prApp_LiveCell_By_MapID] 
  @facet smallint,
  @map smallint
AS
BEGIN
  SELECT *
  FROM LiveCell
  WHERE facet=@facet AND map=@map 
END

And of course needed to modify the call in the code to match.

Assets/DragonsSpine/DAL/DBWorld.cs
148
149
150
151
152
using (SqlStoredProcedure sp = new SqlStoredProcedure("prApp_LiveCell_by_MapID", tempConnection)) {
  sp.AddParameter("@facet", SqlDbType.Int, 4, ParameterDirection.Input, 0);
  // sp.AddParameter("@land", SqlDbType.Int, 4, ParameterDirection.Input, 0);
  sp.AddParameter("@map", SqlDbType.Int, 4, ParameterDirection.Input, mapNum);
  using (DataTable dtCells = sp.ExecuteDataTable()) {

Ditto NPCs. So now we can easily pull from any map we want.

Switching maps
#

The managers need to handle switching between maps. We’ll start them out on map “-1” and add a setter and coroutine in a by-now familiar pattern.

Assets/Managers/MapManager.cs
20
21
22
23
24
25
26
27
28
29
30
private int mapNum = -1;
public int MapNum {
  get { return mapNum; }
  set {
    if (mapNum != value) {
      mapNum = value;
      StopCoroutine("LoadMap");
      if (mapNum != -1) StartCoroutine("LoadMap");
    }
  }
}
Assets/Managers/MapManager.cs
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
IEnumerator LoadMap() {
  lock (cellLock) {
    lastRoundSeen = 0;
    foreach (CellScript cs in cell_objects.Values)
      cs.gameObject.SetActive(false);
    num_cells = 0;
    cell_objects.Clear();
    cellKeyList.Clear();
    cells.Clear();
    cellsKeys.Clear();

    InitialMapLoading();
    nextDBUpdate = Time.time + dbUpdateDelta;
  }
  yield return null;
}

The code that was originally only called once has moved into InitialMapLoading, and we clear everything out (except the object pool and material dictionary) before calling it for the new map. You may notice a lock which needed to be added; in the MapManager we are sharing the various cell structures with the DB access thread, so we need some safety.

Something very similar was done in NpcManager, minus the locks because we’re more safely passing lists around there.

Material Caching
#

Map-changing performance was initially quite bad on some maps, until I switched the NpcManager over to keeping a dictionary of Materials that persisted.

Assets/Managers/NpcManager.cs
197
198
199
200
201
202
203
204
205
if (!npcLiveMaterials.ContainsKey(npc.name)) {
  Material npcLiveMaterial = Resources.Load("Materials/" + npc.name, typeof(Material)) as Material;
  if (npcLiveMaterial == null) {
    print("Couldn't find live Material for NPC name: " + npc.name);
    npcLiveMaterial = Resources.Load("Materials/anonymous", typeof(Material)) as Material;
  }
  npcLiveMaterials[npc.name] = npcLiveMaterial;
}
npc.liveMaterial = npcLiveMaterials[npc.name];

I had been doing this in MapManager the whole time, but was kind of surprised at the impact that using it in NpcManager had. I guess calls to Resources.Load are really as expensive as you’d think.

Defining some vantage points
#

Just to make sure we have a good view of each new map when we switch to it, I manually added an initial camera position for each via the editor.

Yes, this is kind of lame.
Yes, this is kind of lame.

Note that these would change between aspect ratios; I did these for 16:9.

And a keypress to cycle
#

Assets/Managers/GUIManager.cs
33
34
35
36
37
38
39
40
41
if (Input.GetKeyDown(KeyCode.M)) {
  mapNum += 1;
  if (mapNum > 12) mapNum = 0;
  if (mapNum == 9) mapNum = 10; // for some reason there's no map 9
  if (mapOverlooks.Length > mapNum)
    mainCamera.MoveToPosition(mapOverlooks[mapNum]);
  mapManager.MapNum = mapNum;
  npcManager.MapNum = mapNum;
}

And some new Materials
#

For cell types that didn’t exist on the first few maps.

All for a cool gif
#

Not even that great at this resolution.
Not even that great at this resolution.

(Pauses edited out for your enjoyment. We can’t really load new maps that fast. Yet.)

Well, not just for this cool gif. Now we have all of the plumbing in place to switch maps on the fly, in search of action or to follow a character going through a portal or whatever.


More to come
More to come

Day 30 code - visualizer

Day 30 code - server