Skip to main content
  1. Posts/

Day 29 - Pooling Worlds

OldDays ste-reez-muvi Unity csharp

Now that Autumn is finally here, I declare this the Pumpkin Spice Blog Post.

Coding
#

(The actual first thing I did was make the MapManager only pull changed cells on each update, and not to load the map file anymore, but that’s too boring to detail here.)

1. Generic object pooling
#

First, I converted the NpcManager and MapManager over to using more generic object pools (see below under Learning). Not too exciting, but allows for the next step. The only real wrinkle I ran into, since this method has the not-in-use objects inactive at the GameObject level, is that anything that triggered a coroutine would fail. That required pushing things around a bit so that NPCs were definitely active before I’d try to modify their health or hatred.

Assets/Managers/NpcManager.cs
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
  } else {
    tempNpc = npcPooler.GetPooledObject().GetComponent<NpcScript>();
    tempNpc.Reset();
    tempNpc.npcManager = this;
    tempNpc.npcId = npc.worldNpcID;
    tempNpc.name = npc.Name;
    SetMaterials(tempNpc);
    tempNpc.toBeSeen = (position.z <= mapManager.zTop + 1);                    
    npcScripts[npc.worldNpcID] = tempNpc;
  }
  tempNpc.gameObject.SetActive(true);
  tempNpc.cell = cell;
  tempNpc.newPosition = position;
  tempNpc.lastActiveRound = npc.lastActiveRound;
  tempNpc.UpdateMaterial(maxGameRound);
  tempNpc.Hits = npc.Hits;
  tempNpc.HitsFull = npc.HitsFull;
  tempNpc.MostHatedId = npc.mostHatedId;
  tempNpc.HasMostHated = npc.hasMostHated;
}
Assets/Managers/MapManager.cs
88
89
90
91
92
93
94
if (cellNeedsTransform[c]) {
  // Instantiate this one
  Vector3 position = CLUtils.CellLocToVector3(new CellLoc(cells[c].x, cells[c].y, cells[c].z), 0);

  tempCell = cellPooler.GetPooledObject().GetComponent<CellScript>();
  tempCell.mapManager = this;
  tempCell.newPosition = position;
Assets/lib/ObjectPooler.cs
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// With thanks to Mike Geig and http://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/object-pooling

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ObjectPooler : MonoBehaviour {

  // public static ObjectPooler current;
  public GameObject pooledObject;
  public int pooledAmount = 400;
  public bool willGrow = true;
  public int currentSize = 0;

  List<GameObject> pooledObjects;

  void Awake() {
    // current = this;
  }

  void Start () {
    pooledObjects = new List<GameObject>();
    for (int i = 0; i < pooledAmount; i++) {
      GameObject obj = (GameObject)Instantiate(pooledObject);
      obj.SetActive(false);
      pooledObjects.Add(obj);
    }
    currentSize = pooledObjects.Count;
  }

  public GameObject GetPooledObject() {
    for (int i = 0; i < pooledObjects.Count; i++) {
      if (!pooledObjects[i].activeInHierarchy) {
        return pooledObjects[i];
      }
    }
    if (willGrow) {
      GameObject obj = (GameObject)Instantiate(pooledObject);
      pooledObjects.Add(obj);
      currentSize = pooledObjects.Count;
      return obj;
    }
    return null;
  }
}

I’m not making the ObjectPooler a singleton because, well, I have two of them. And I keep a count of the objects handy for reference/debugging.

2. Different maps
#

Until now, we’ve always been pulling map 0, the original Island of Kesmai. I did this initially to keep things simple, but it’s time to open things up. The DB already has the data for every map, we just need to let ourselves read it:

Assets/DragonsSpine/DAL/DBNPC.cs
104
105
106
107
108
109
110
111
112
public static List<NPCLite> GetAllNpcs(int mapNum)
{
  List<NPCLite> npclist = new List<NPCLite>();
  
  using (SqlConnection tempConnection = DataAccess.GetSQLConnection())
  using (SqlStoredProcedure sp = new SqlStoredProcedure("prApp_LiveNPC_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);
Assets/DragonsSpine/DAL/DBWorld.cs
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
    public static int UpdateCellDict(Dictionary<CellLoc, CellLite> cellDict, int mapNum, int sinceRound) {
      int numUpdated = 0;
      CellLoc tmpCellLoc;
      List<CellLite> cellList = GetUpdatedLiveCells(mapNum, sinceRound);
      foreach (CellLite cell in cellList) {
        tmpCellLoc = new CellLoc(cell.x, cell.y, cell.z);
        cellDict[tmpCellLoc] = cell;
        numUpdated += 1;
      }
      return numUpdated;
    }

    public static List<CellLite> GetUpdatedLiveCells(int mapNum, int sinceRound) {
      List<CellLite> cellList = new List<CellLite>();
      int tmpRound = 0;
      using (SqlConnection tempConnection = DataAccess.GetSQLConnection())
      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);
Assets/Managers/GUIManager.cs
10
11
12
13
14
15
16
public int mapNum;

void Awake () {
  instance = this;
  mapManager.mapNum = mapNum;
  npcManager.mapNum = mapNum;
}

There’re updates to NpcManager and MapManager to pass the mapNum through, of course.

3.0 Pretty Places
#

The Plains of Leng
The Plains of Leng
The Ice Floes of Axe Glacier
The Ice Floes of Axe Glacier
The Forests of Oakvael
The Forests of Oakvael

Learning
#


Playing
#

  • The Talos Principle continues to deliver on the puzzle front. The narrative also has me somewhat fascinated, and delivering it partially through retro green-on-black text terminals scattered throughout the world is a delicious touch.
  • Puppeteer is visually awesome; I’m not good at it, but love watching the “this is a puppet show on a stage” premise being maintained.

More to come
More to come

Day 29 code - visualizer