Day 13 - Limited Autonomy

Time for the NPC behavior to separate out a bit.


Introducing NpcScript

Up to now, the NPC prefab didn’t have any scripting attached to it. Everything was done via the MapManager. Let’s change that, in the interest of future code sanity and flexibility. We’ll attach a script to the prefab and call it NpcScript:

Assets/NpcScript.csGitLab
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
using UnityEngine;
using System.Collections;

public class NpcScript : MonoBehaviour {

    public Vector3 oldPosition, newPosition;
    public Vector3 oldScale, newScale;
    public float timeSinceStable;

    void Start () {
        oldPosition = newPosition = transform.position;
        oldScale = newScale = transform.localScale;
        timeSinceStable = 0f;
    }
    
    void Update () {
        timeSinceStable += Time.deltaTime;
        if (transform.position != newPosition) {
            transform.position = Vector3.Slerp(oldPosition,newPosition,timeSinceStable);
            if (timeSinceStable >= 1f) transform.position = newPosition; // hmm
        } else {
            if (transform.localScale != newScale) {
                transform.localScale = Vector3.Slerp(oldScale,newScale,timeSinceStable - 1f);
                if (timeSinceStable >= 2f) transform.localScale = newScale; // hmm
            } else {
                    timeSinceStable = 0f;
                    oldPosition = transform.position;
                    oldScale = transform.localScale;
            }
        }
    }
}

For now, all it does it wait for newPosition or newScale to be altered, and then moves to the new position/scale over the next two seconds. (Note: I had to add the two “hmm” lines because the two Vector3s were getting close but never close enough. Surprising behavior from Slerp; I had assumed that once t exceeded 1, the returned Vector3 would be equal to b.) But this won’t do anything as long as MapManager is directly changing the position and localScale of the Npc transform, so we make changes like this:

Managers/MapManager.csGitLab
204
205
206
207
208
    if (npcTransforms.ContainsKey(npc.worldNpcID)) {
        NpcScript ns = npcTransforms[npc.worldNpcID].GetComponent<NpcScript>();
        ns.newPosition = position;
        // npcTransforms[npc.worldNpcID].position = position;
    } else {

It’s a little kludgy right now, but does it work? Yes.


Separation Anxiety, Part One

We still want a central manager for NPCs, so we’ll split out from MapManager and make NpcManager. Not a lot of actual code change, just separation, but something to point out: Each manager has an UpdateZ method; the one in mapManager calls the one in npcManager.

Managers/MapManager.csGitLab
171
172
173
174
175
176
177
178
179
180
181
182
183
public void UpdateZ(float z) {
    Renderer currRend;
    foreach (Vector3 v in cell_transforms.Keys) {
        currRend = cell_transforms[v].GetComponent<Renderer>();
        currRend.enabled = (v.z <= z);
    }
    npcManager.UpdateZ(z);
    foreach (Vector3 v in portalTransforms.Keys) {
        currRend = portalTransforms[v].GetComponent<Renderer>();
        currRend.enabled = (v.z <= z);
    }
    zTop = z;
}

That done, I switch the NpcManager from instantiating and tracking NPC transforms to cloning script instances directly. This allows me to do stuff like this:

Managers/NpcManager.csGitLab
68
69
70
71
72
73
74
75
    if (!npcScripts.ContainsKey(npc.worldNpcID)) {
        NpcScript tempNpc = (NpcScript) Instantiate(npcScript);
        tempNpc.npcId = npc.worldNpcID;
        tempNpc.name = npcName;
        npcScripts[npc.worldNpcID] = tempNpc;
    }
    npcScripts[npc.worldNpcID].newPosition = position;
    npcScripts[npc.worldNpcID].lastActiveRound = npc.lastActiveRound;

So I can see stuff like this:


Day 13 code - client