Day 35 - Rise (and Stumble) of the Dudes


Coding

Firstly, that thick NPC thing was not so difficult to track down.

Assets/Managers/NpcManager.cslink
231
thisNpcScript.newScale = new Vector3(1.0f / dimension, 1.0f / dimension, thisNpcScript.transform.localScale.z);

All of the NPCs are 0.1 units thick, and 0.1 decimal is a non-terminating binary value. Reading the value out of the engine, doing math on it, and plugging it back in requires some care. Over decent intervals of time, the error was building up, so we got thick NPCs. It’s hardcoded now.


Using the test code I threw together, and a little tweak to give them all the same material, it’s easy to get a horde of dudes wandering blindly north-ish through town.

experiment0.rblink
80
81
82
83
84
85
86
87
88
89
90
91
  9999.times do
    host.cmd({"String" => ['w','nw','n','ne','e'].sample, "Match" => / ->/}) { |c| puts "14 #{c.gsub(/\e/, "[ESC]")}" }
  end
end

threads = []
20.times do
  threads << Thread.new do
    have_fun
  end
end
threads.each { |thr| thr.join }

But why are some of them rendering as wolves?

Worse yet, why am I rendering as a wolf?

Not just a visual defect, but a very specific wolf. All symptoms point to a problem with the object pool.

Assets/Managers/NpcManager.cslink
172
173
174
175
176
177
178
179
180
181
182
183
184
if (npcScripts.ContainsKey(npc.worldNpcID)) {
    tempNpc = npcScripts[npc.worldNpcID];
} 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);

I’m beginning to suspect that nothing before the SetActive(true) is actually happening, or at least isn’t having a real effect. Let’s check that theory.

Assets/Managers/NpcManager.cslink
190
191
192
tempNpc.gameObject.SetActive(true);
if (recycledNpc) print("Recycled NPC has ID " + tempNpc.npcId + " when it should be " + npc.worldNpcID);
if (tempNpc.npcId != npc.worldNpcID) Debug.Break();

No good, it always has the right ID. But some further playing saw my PC being inactive at the gameObject level. How could that be happening?

Assets/Managers/NpcManager.cslink
173
174
175
176
177
178
if (npcScripts.ContainsKey(npc.worldNpcID)) {
    tempNpc = npcScripts[npc.worldNpcID];
    if (!tempNpc.gameObject.activeInHierarchy) {
        print("NPC " + npc.worldNpcID + " not active!");
        Debug.Break();
    }

Well, that triggers a bunch if we cycle through some gangs of dudes. So we’re pulling references out of the npcScripts dictionary even if they’ve been thrown back in the recycler. I think we can fix that.

Assets/Managers/NpcManager.cslink
155
156
157
158
159
160
161
162
163
if (npc.lastActiveRound < maxGameRound - 10) {
    NpcScript tempNpcScript;
    if (npcScripts.TryGetValue(npc.worldNpcID, out tempNpcScript)) {
        tempNpcScript.gameObject.SetActive(false);
    }
    npcScripts.Remove(npc.worldNpcID); // oops, forgot to do this
    npcLocations.Remove(npc.worldNpcID);
    if (npc.isPC) activePcs.Remove(npc.worldNpcID);
} else {

and now everything works as it should. I’m beginning to look forward to rewriting most of this code with what I’ve learned, but that will have to wait.


Day 35 code - tests Day 35 code - visualizer

Decimal/Binary Converter