- Home /
Dictionary being cleared when reaching end of Update.
Hello everyone, I have an update function below that is supposed to be tracking bodies from the Kinect.
However I have an issue where the _Bodies dictionary doesn't store anything and is always cleared when the Update loop starts back from the top. Once it gets to this point: List knownIds = new List (_Bodies.Keys);
_Bodies is already at a count of zero. So the code that is supposed to remove a key value pair if it's not being tracked by the Kinect anymore doesnt run. Also this means that it just keeps instantiating new objects over and over again. Can anyone see why my Dictionary might not be storing values properly?
private Dictionary<ulong, GameObject> _Bodies = new Dictionary<ulong, GameObject> ();
void Update()
{
if (BodySourceManager == null) {
return;
}
_BodyManager = BodySourceManager.GetComponent<BodySourceManager> ();
if (_BodyManager == null) {
return;
}
Kinect.Body[] data = _BodyManager.GetData ();
if (data == null) {
return;
}
List<ulong> trackedIds = new List<ulong> ();
foreach (var body in data) {
if (body == null) {
continue;
}
if (body.IsTracked) {
trackedIds.Add (body.TrackingId);
}
}
List<ulong> knownIds = new List<ulong> (_Bodies.Keys);
// First delete untracked bodies
foreach (ulong trackingId in knownIds) {
if (!trackedIds.Contains (trackingId)) {
Destroy (_Bodies [trackingId]);
_Bodies.Remove (trackingId);
}
}
foreach (var body in data) {
if (body == null) {
continue;
}
if (body.IsTracked)
{
if (!_Bodies.ContainsKey (body.TrackingId)) {
_Bodies [body.TrackingId] = InstantiateMyObject(body);
}
RefreshBodyObject (body);
}
}
}
_Body$$anonymous$$anager = BodySource$$anonymous$$anager.GetComponent<BodySource$$anonymous$$anager> ();
Put that in Start().
So, whats this RefreshBodyObject and whats in that BodySource$$anonymous$$anager? Could they cause the problems?
The BodySource$$anonymous$$anager was included in the $$anonymous$$inectSD$$anonymous$$ and just opens the data connection to the $$anonymous$$inect and gets the data from it.
RefreshBodyObject is just this:
private void RefreshBodyObject ($$anonymous$$inect.Body body)
{
m_BodyPositionX [body.TrackingId] = $$anonymous$$athf.Round (body.Joints [$$anonymous$$inect.JointType.SpineBase].Position.X * 100);
m_BodyPositionY [body.TrackingId] = $$anonymous$$athf.Round (body.Joints [$$anonymous$$inect.JointType.SpineBase].Position.Y * 200);
m_BodyDistance [body.TrackingId] = $$anonymous$$athf.Round (body.Joints [$$anonymous$$inect.JointType.SpineBase].Position.Z * 100);
}
It just takes in the body and updates a completely different set of lists to track the players movement in X,Y,Z.
$$anonymous$$aybe this is relevant, maybe not.
http://forum.unity3d.com/threads/dictionary-empty-upon-play.380184/
http://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.OnBeforeSerialize.html
Answer by meat5000 · Feb 16, 2016 at 01:22 PM
Everytime you use 'new' you are overwriting what was there before. If you want the data to persist this will not work. Maybe this is your intention? I don't know.
Also, you need to make sure your null check is working on _Bodies. Put a Debug.Log before the return to see what the situation is.
The two lists "trackedIds" and "knownIds" I do want overwritten. The only one I want to persist data is the "_Bodies" list. The null check is just there in case the $$anonymous$$inect isn't connected so it doesn't just throw null errors. Theres always a list of 6 populated "bodies" from the $$anonymous$$inect when it's connected and running.
I don't see anything that should be clearing the _Bodies list but for some reason between update loops its being cleared every time by the very top of the loop.
Correct me if I'm being stupid here but I don't see _Bodies.Add
anywhere.
The following: _Bodies [body.TrackingId] = Instantiate$$anonymous$$yObject(body);
Does the same thing as: _Bodies.Add(key, value);
Once it passes that point _Bodies does add the object to my dictionary. But the second it reaches the top of the update loop its empty again.
well if its working just fine inside the Update, then its not the Update method you should have shown us....You should also check FixedUpdate, LateUpdate and any message that can be called at least once per frame like OnCollisionStay, OnTriggerStay, or any coroutines
None of those functions are present in my class. Nor does any other class reference the list.
Answer by JoshuaMcKenzie · Feb 17, 2016 at 11:42 AM
Remember that you are using an external Hardware sensor which isn't managed by Unity, so my bet is that the Kinect is likely updating at a much slower rate than unity. in the frames that things are getting deleted is likely due to the Kinect is still generating the body for its next update (which is asynchronous to Unity's Update). I've done a quick seach and I've seen that the kinect (not the unity wrapper, but the SDK itself) doesn't present a body data on every frame (30 or 60 fps), but only on the frames that it is ready (usually much lower some examples I've seen are at 16fps).
what this likely means is that you shouldn't be adding/removing Gameobjects based on tracked bodies inside an Update() call. instead try having the Gameobject always instantiated, but either hidden or moved off screen.
Or only go by the last updated frame. you likely want to get the last updated frame like is done in this guy's body manager
That body manager is the same one included in the $$anonymous$$inect SD$$anonymous$$ that I am using, the class I have above was also just adapted from their SD$$anonymous$$ example. I followed instantiating when they did, I thought it might be because of the update discrepancy as well. I changed it around a bit so I never store a reference to the actual bodies tracking id, but a copy of it and its still being cleared.
@$$anonymous$$ Hofer, what you could do to better track where the _Bodies is getting cleared is turn the _Bodies into a property with a getter and setter then place a debug.log in the setter so that you can catch any and all attempts that set the dictionary.
Not a solution itself but having it as a property can give you the control you need to figure out what is happening, then from there you can get a solution.
Yes, i would call it the debugging trick "#42" - the answer to all (most) debug problems ^^.
Also don't just place a Debug.Log in the setter, the getter is usually more interesting for reference types.
+1
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Array member treated as null even though it is not. 1 Answer