/// <summary> /// Retrieve all GameObject with a particular Classifications. /// </summary> /// <param name="classification">A classification the GameObject must have (although not exclusively).</param> /// <returns>A list of all GameObject which have the specified Classifications.</returns> public List <GameObject> GetGameObjectsOfClassification(GameObjectDefinition.Classifications classification) { return(mGameObjectsByClassification[classification]); }
/// <summary> /// Should be called once per frame. /// </summary> /// <param name="gameTime">The amount of time passed since last update.</param> public void Update(GameTime gameTime) { #if DEBUG // Draw cell boundaries. // Int32 size = mNumCells * mCellSize; for (Int32 y = 0; y < mNumCells; y++) { DebugShapeDisplay.pInstance.AddSegment(new Vector2(0, y * mCellSize), new Vector2(size, y * mCellSize), Color.Black); } for (Int32 x = 0; x < mNumCells; x++) { DebugShapeDisplay.pInstance.AddSegment(new Vector2(x * mCellSize, 0), new Vector2(x * mCellSize, size), Color.Black); } #endif DebugMessageDisplay.pInstance.AddDynamicMessage("Objects Rendered: " + mLastNumObjectsRendered); mCurrentUpdateState = UpdatePhase.Update; // Keep track of how many objects were updated this frame. int count = 0; // Some behaviours require some logic to be done prior to the standard update. This is their chance. // for (int i = 0; i < mGameObjects.Count; i++) { if (mGameObjects[i].pDoUpdate) { mGameObjects[i].PreUpdate(gameTime); } } // Update every object we are managing. // for (int i = 0; i < mGameObjects.Count; i++) { if (mGameObjects[i].pDoUpdate) { mGameObjects[i].Update(gameTime); } count++; } // A final chance to update behaviours after all the updates have been completed. // for (int i = 0; i < mGameObjects.Count; i++) { if (mGameObjects[i].pDoUpdate) { mGameObjects[i].PostUpdate(gameTime); } } DebugMessageDisplay.pInstance.AddDynamicMessage("Updated " + count + " GameObjects"); mCurrentUpdateState = UpdatePhase.Remove; // Now loop through our list of objects which need to be removed and // remove them. // for (int i = 0; i < mGameObjectsToRemove.Count; i++) { // If this is a GameObject that was spawned through a Factory then it needs to be // returned to that Factory. if (mGameObjectsToRemove[i].pFactoryInfo.pIsManaged) { GameObjectFactory.pInstance.RecycleTemplate(mGameObjectsToRemove[i]); } // See if this is also going to be referenced in the dynamic objects list. if (!mGameObjectsToRemove[i].pIsStatic) { mDynamicGameObjects.Remove(mGameObjectsToRemove[i]); } // See if this is going to be reference in the static objects list. if (mGameObjectsToRemove[i].pIsStatic) { // Figure out which cell this object would be in. Vector2 index = CellIndexFromPosition(mGameObjectsToRemove[i].pPosition); // Remove it from the cell it should be in. mStaticGameObjects[(Int32)index.X, (Int32)index.Y].Remove(mGameObjectsToRemove[i]); } for (Int32 tag = 0; tag < mGameObjectsToRemove[i].pClassifications.Count; tag++) { mGameObjectsByClassification[(GameObjectDefinition.Classifications)tag].Remove(mGameObjectsToRemove[i]); } // What happens if someone adds and removes an element within the same // update? It would mean we are about to remove an item that hasn't // actually been added yet! To get around this flaw, we will attempt to // remove the item from the main list and if that fails, try to remove it // from the list of items about to be added. if (mGameObjectsToRemove[i] != null && mGameObjects.Remove(mGameObjectsToRemove[i]) == false) { if (mGameObjectsToAdd.Remove(mGameObjectsToRemove[i]) == false) { //System.Diagnostics.Debug.Assert(false, "Attempting to remove a game object which isn't in any of the managed lists."); } } } mCurrentUpdateState = UpdatePhase.Add; // Loop through all the game objects that exist. We want to insert the new game objects // in the order that they were added, based on render priority. If the new object shares // a render priority with another object, it is inserted in front of the first same-priority // object it hits. // // This bit of code assumes that the mGameObjectsToAdd and mGameObjects are both sorted // based on render priority. // int curIndex = 0; for (int i = 0; i < mGameObjectsToAdd.Count; i++) { // Check if this is a dynamic object which isn't already being managed by this list. if (!mGameObjectsToAdd[i].pIsStatic) { System.Diagnostics.Debug.Assert(!mDynamicGameObjects.Contains(mGameObjectsToAdd[i]), "Attempting to add GameObject already in mDynamicGameObjects."); mDynamicGameObjects.Add(mGameObjectsToAdd[i]); } // Has this object been flagged as being static? if (mGameObjectsToAdd[i].pIsStatic) { // Figure out which cell this object would be in. Vector2 index = CellIndexFromPosition(mGameObjectsToAdd[i].pPosition); System.Diagnostics.Debug.Assert(!mStaticGameObjects[(Int32)index.X, (Int32)index.Y].Contains(mGameObjectsToAdd[i]), "Attempting to add GameObject already in mStaticGameObjects."); mStaticGameObjects[(Int32)index.X, (Int32)index.Y].Add(mGameObjectsToAdd[i]); } for (Int32 tagIndex = 0; tagIndex < mGameObjectsToAdd[i].pClassifications.Count; tagIndex++) { GameObjectDefinition.Classifications tag = mGameObjectsToAdd[i].pClassifications[tagIndex]; mGameObjectsByClassification[tag].Add(mGameObjectsToAdd[i]); } // If this game object is already in the list, don't add it again. if (!mGameObjects.Contains(mGameObjectsToAdd[i])) { bool alreadyAdded = false; // Loop through all the currently exisiting game objects. We continue moving // forward even after inserting a new object. This can be done because we assume // the mGameObjectsToAdd is also sorted by render priority, which means the next // element must be placed somewhere after the current one. for (; curIndex < mGameObjects.Count; curIndex++) { if (mGameObjectsToAdd[i].pRenderPriority < mGameObjects[curIndex].pRenderPriority) { // We have found the proper place for this element. mGameObjects.Insert(curIndex, mGameObjectsToAdd[i]); // We don't want to test against the elemt we just added. Since it was // inserted at i, the object we just compared against is actually at i + 1 // now. Let's start the next comparison there. curIndex++; alreadyAdded = true; break; } } if (!alreadyAdded) { // If we make it to this point all the remaining elements have a greater or equal // render priority to the highest priority item already existing. // This will also take care of the cases where this is the first item being added. mGameObjects.Add(mGameObjectsToAdd[i]); // We don't want to test against the element we just added. Since it was // inserted at i, the object we just compared against is actually at i + 1 // now. Let's start the next comparison there. curIndex++; } } } mCurrentUpdateState = UpdatePhase.OnRemove; if (mGameObjectsToRemove.Count != 0) { // At this point all objects for the frame have been removed from // the GameObjectManager. This is an ideal time to give objects // a chance to do some cleanup which requires objects to // be removed (eg. Delete stuff). for (Int32 i = 0; i < mGameObjectsToRemove.Count; i++) { mGameObjectsToRemove[i].OnRemove(); } mGameObjectsToRemove.Clear(); } mCurrentUpdateState = UpdatePhase.OnAdd; if (mGameObjectsToAdd.Count != 0) { // At this point all objects for the frame have been added to // the GameObjectManager. This is an ideal time to give objects // a chance to do some initization which requires objects to // be added (eg. BroadCastMessage). for (Int32 i = 0; i < mGameObjectsToAdd.Count; i++) { mGameObjectsToAdd[i].OnAdd(); } mGameObjectsToAdd.Clear(); } mCurrentUpdateState = UpdatePhase.None; if (mGameObjectsToRemoveNextFrame.Count > 0) { mGameObjectsToRemove.AddRange(mGameObjectsToRemoveNextFrame); mGameObjectsToRemoveNextFrame.Clear(); } if (mGameObjectsToAddNextFrame.Count > 0) { mGameObjectsToAdd.AddRange(mGameObjectsToAddNextFrame); mGameObjectsToAddNextFrame.Clear(); } }