301 Days (redux)

Another metric leap year of gamedev experiments and such

Sep 23, 2015 - OldDays ste-reez-muvi

Day 19 - Random chores

A few things to do, nothing too exciting.

Managing managed memory for management

Most NPC AI too.

Added some code to start spitting out the memory being used pre- and post- a forced garbage collection after 15 seconds, then pause the game when the post-GC memory stops changing. With the server not running, and me not touching anything, we should get semi-consistent results, right?

Assets/Managers/NpcManager.cs GitLab
56
57
58
59
60
61
62
63
64
65
66
67
if (Time.time > 15f) {
    if (totalMemory == 0f) { // first time through
        totalMemory = GC.GetTotalMemory(false);
        print("Total Memory at time " + Time.time + "  pre-GC: " + totalMemory.ToString("N"));
    }
    totalMemory = GC.GetTotalMemory(true);
    if (oldTotalMemory == totalMemory) {
        print("Total Memory at time " + Time.time + " post-GC: " + totalMemory.ToString("N"));
        Debug.Break();
    }
    oldTotalMemory = totalMemory;
}
  • First run:
    • Total Memory at time 15.00965 pre-GC: 27,811,840.00
    • Total Memory at time 15.14369 post-GC: 19,075,070.00
  • Second run:
    • Total Memory at time 15.00806 pre-GC: 24,526,850.00
    • Total Memory at time 15.15492 post-GC: 19,468,290.00
  • Third run:
    • Total Memory at time 15.01008 pre-GC: 24,870,910.00
    • Total Memory at time 15.15714 post-GC: 19,496,960.00
  • Fourth run:
    • Total Memory at time 15.00175 pre-GC: 24,616,960.00
    • Total Memory at time 15.13237 post-GC: 19,505,150.00

…so at least we have a baseline as we make changes that will take less/more memory. Commented out for now, wondering if I’ll actually use it before just switching to Unity 5 and using the built-in Profiler.


Cellular cleanup

Actual life is never so tidy.

Like we did with NPCs, let’s cut down on the size of some of the Cells we’re keeping around:

Assets/DragonsSpine/World/Cell.cs GitLab
2591
2592
2593
2594
2595
2596
2597
public struct CellLite {
    public string displayGraphic;
    public bool   isMapPortal;
    public short  x;
    public short  y;
    public int    z;
}
Assets/Managers/MapManager.cs GitLab
220
221
222
223
224
225
226
227
228
229
230
231
cellKeyList = new List<string>(ourMap.cells.Keys);
cells.Clear();
foreach (string k in cellKeyList) {
    Vector3 mapPosition = new Vector3(ourMap.cells[k].X, ourMap.cells[k].Y, ourMap.cells[k].Z);
    CellLite newCell; 
    newCell.displayGraphic = ourMap.cells[k].DisplayGraphic;
    newCell.isMapPortal = ourMap.cells[k].IsMapPortal;
    newCell.x = ourMap.cells[k].X;
    newCell.y = ourMap.cells[k].Y;
    newCell.z = ourMap.cells[k].Z;
    cells.Add(mapPosition, newCell);
}

Doesn’t help too much (not like the NPCLite change), and only points to how much I need to overhaul Cell handling in general.


More coroutining

The Black Knight seems unaware of his Health counter.

Now that Hatred is handled in a coroutine, Damage should join it. This coroutine is even simpler.

Assets/NpcScript.cs GitLab
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public int Hits {
    get { return hits; }
    set {
        if (hits != value) {
            hits = value;
            StopCoroutine("Damage");
            StartCoroutine("Damage");
        }
    }
}

public int HitsFull {
    get { return hitsFull; }
    set {
        if (hitsFull != value) {
            hitsFull = value;
            StopCoroutine("Damage");
            StartCoroutine("Damage");
        }
    }
}

public float Health {
    get { return Mathf.Clamp((float) hits / (float) hitsFull, 0f, 1f); }
}
Assets/NpcScript.cs GitLab
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
IEnumerator Damage () {
    while (Health < 1f && !presumedDead && hits > 0f) {
        if (myDamage == null) {
            myDamage = Instantiate(damagePrefab, 
                                   Vector3.zero,
                                   Quaternion.identity) as Transform;
            myDamage.parent = this.transform;
            myDamage.localPosition = new Vector3(0f, 0f, 0.1f);
            myDamageRend = myDamage.GetComponent<Renderer>();
        }
        myDamage.localScale = new Vector3(1f, 1f - Health, 1f);
        myDamageRend.enabled = toBeSeen;
        yield return null;
    }
    if (myDamage != null) myDamageRend.enabled = false;
}

The tricky bit: As the NPC is being generated/reset, hits and hitsFull are set individually, so there’s a time when we would instantiate a damage indicator unnecessarily. We can avoid that by defaulting hitsFull to 1 and hits to maxint.

Assets/NpcScript.cs GitLab
84
85
86
87
88
89
90
91
92
93
94
95
96
public void Reset() {
    oldPosition = newPosition = transform.position;
    oldScale = newScale = transform.localScale;
    timeSinceStable = 0f;
    toBeSeen = true;
    npcId = 0;
    name = "undefined";
    lastActiveRound = 0;
    hitsFull = 1; hits = int.MaxValue; // So that during initialization our health is always full.
    presumedDead = false;
    hasMostHated = false;
    mostHatedId = 0;
}

Other

Whatcha Playin'?

Currently, Volume from Mike Bithell and friends. Just playing through the story, and I’m not very good, but I’m completely hooked. Have to set a timer so I don’t “One more level…” myself into oblivion.

Good news

Since upgrading to Unity 4.6.8, I haven’t had any more lockups of MonoDevelop. Yay!

Sorry

Random Autumn illness and busy times at work have made these “days” way less frequent when they should be. Hope to improve on that.


More to come

Day 19 code - client