// Adds a MovementSegment to all the proper cells in the grid to account for the creature's size by wrapping it // with a SegmentWrapper and adding the wrapper to the proper cells. When we calculate a creature's movement we have // to mark all the cells in a square around the center that their size covers as occupied. This function reserves // all the cells that a given segment would cover for a creature. internal void AddSegment(MovementSegment segment) { // Figure out how many cells on either side of the center we need to reserve var cellRadius = segment.State.CellRadius; if (segment.Previous == null) { // Beginning of a segment // We should have never started in a position where the radius of the organism // went outside the bounds of the universe Debug.Assert(segment.GridX >= 0 && segment.GridY >= 0 && segment.GridX - cellRadius >= 0 && segment.GridY - cellRadius >= 0 && segment.GridX + cellRadius < GameEngine.Current.GridWidth && segment.GridY + cellRadius < GameEngine.Current.GridHeight); Debug.Assert(segment.EntryTime == 0); StartSegments.Add(segment); } else { Debug.Assert(segment.EntryTime != 0); // If this segment pushes the organisms radius outside the bounds of the universe, clip it now // and don't bother evaluating it later if (segment.GridX < 0 || segment.GridY < 0 || segment.GridX - cellRadius < 0 || segment.GridY - cellRadius < 0 || segment.GridX + cellRadius > GameEngine.Current.GridWidth - 1 || segment.GridY + cellRadius > GameEngine.Current.GridHeight - 1) { segment.Previous.Next = null; return; } } // Do the top and bottom rows ArrayList list; SegmentWrapper wrapper; for (var x = segment.GridX - cellRadius; x <= segment.GridX + cellRadius; x++) { // *** Top row of square *** // Make a unique hash for every square in the grid var hash = (x << 16) | (segment.GridY - cellRadius); // retrieve the set of SegmentWrappers that are already in the cell of the grid list = (ArrayList) _gridSquares[hash]; if (list == null) { // None exist yet, create an ArrayList to hold them list = new ArrayList(); _gridSquares[hash] = list; } // Make sure two organisms didn't start in the same place Debug.Assert(segment.EntryTime != 0 || !HasStartingSegments(list)); // Create a wrapper for this segment, give it a backpointer to the arraylist that contains // all the segments in this cell wrapper = new SegmentWrapper(segment, list); // Add the SegmentWrapper itself to the list of segments in this cell list.Add(wrapper); // Now add the SegmentWrapper to our master sorted list of all SegmentWrappers anywhere _sortedList.Add(wrapper); // CellsLeftToResolve is there to recognize the fact that an animal overlaps many squares. // Until you know that it can occupy all of the squares it moves into, it can't move into // any of them. This property keeps track of whether we have resolved them all or not. // Here, we are adding one to it for every cell we occupy with this segment. segment.CellsLeftToResolve++; // *** Bottom row of square *** hash = (x << 16) | (segment.GridY + cellRadius); list = (ArrayList) _gridSquares[hash]; if (list == null) { list = new ArrayList(); _gridSquares[hash] = list; } // Make sure two organisms didn't start in the same place Debug.Assert(segment.EntryTime != 0 || !HasStartingSegments(list)); wrapper = new SegmentWrapper(segment, list); list.Add(wrapper); _sortedList.Add(wrapper); segment.CellsLeftToResolve++; } // Do left and right columns for (var y = segment.GridY - cellRadius + 1; y <= segment.GridY + cellRadius - 1; y++) { // Make a unique hash for every square in the grid var hash = ((segment.GridX - cellRadius) << 16) | y; list = (ArrayList) _gridSquares[hash]; if (list == null) { list = new ArrayList(); _gridSquares[hash] = list; } // Make sure two organisms didn't start in the same place Debug.Assert(segment.EntryTime != 0 || !HasStartingSegments(list)); wrapper = new SegmentWrapper(segment, list); list.Add(wrapper); _sortedList.Add(wrapper); segment.CellsLeftToResolve++; hash = ((segment.GridX + cellRadius) << 16) | y; list = (ArrayList) _gridSquares[hash]; if (list == null) { list = new ArrayList(); _gridSquares[hash] = list; } // Make sure two organisms didn't start in the same place Debug.Assert(segment.EntryTime != 0 || !HasStartingSegments(list)); wrapper = new SegmentWrapper(segment, list); list.Add(wrapper); _sortedList.Add(wrapper); segment.CellsLeftToResolve++; } }
// Adds a MovementSegment to all the proper cells in the grid to account for the creature's size by wrapping it // with a SegmentWrapper and adding the wrapper to the proper cells. When we calculate a creature's movement we have // to mark all the cells in a square around the center that their size covers as occupied. This function reserves // all the cells that a given segment would cover for a creature. internal void AddSegment(MovementSegment segment) { // Figure out how many cells on either side of the center we need to reserve var cellRadius = segment.State.CellRadius; if (segment.Previous == null) { // Beginning of a segment // We should have never started in a position where the radius of the organism // went outside the bounds of the universe Debug.Assert(segment.GridX >= 0 && segment.GridY >= 0 && segment.GridX - cellRadius >= 0 && segment.GridY - cellRadius >= 0 && segment.GridX + cellRadius < GameEngine.Current.GridWidth && segment.GridY + cellRadius < GameEngine.Current.GridHeight); Debug.Assert(segment.EntryTime == 0); StartSegments.Add(segment); } else { Debug.Assert(segment.EntryTime != 0); // If this segment pushes the organisms radius outside the bounds of the universe, clip it now // and don't bother evaluating it later if (segment.GridX < 0 || segment.GridY < 0 || segment.GridX - cellRadius < 0 || segment.GridY - cellRadius < 0 || segment.GridX + cellRadius > GameEngine.Current.GridWidth - 1 || segment.GridY + cellRadius > GameEngine.Current.GridHeight - 1) { segment.Previous.Next = null; return; } } // Do the top and bottom rows ArrayList list; SegmentWrapper wrapper; for (var x = segment.GridX - cellRadius; x <= segment.GridX + cellRadius; x++) { // *** Top row of square *** // Make a unique hash for every square in the grid var hash = (x << 16) | (segment.GridY - cellRadius); // retrieve the set of SegmentWrappers that are already in the cell of the grid list = (ArrayList)_gridSquares[hash]; if (list == null) { // None exist yet, create an ArrayList to hold them list = new ArrayList(); _gridSquares[hash] = list; } // Make sure two organisms didn't start in the same place Debug.Assert(segment.EntryTime != 0 || !HasStartingSegments(list)); // Create a wrapper for this segment, give it a backpointer to the arraylist that contains // all the segments in this cell wrapper = new SegmentWrapper(segment, list); // Add the SegmentWrapper itself to the list of segments in this cell list.Add(wrapper); // Now add the SegmentWrapper to our master sorted list of all SegmentWrappers anywhere _sortedList.Add(wrapper); // CellsLeftToResolve is there to recognize the fact that an animal overlaps many squares. // Until you know that it can occupy all of the squares it moves into, it can't move into // any of them. This property keeps track of whether we have resolved them all or not. // Here, we are adding one to it for every cell we occupy with this segment. segment.CellsLeftToResolve++; // *** Bottom row of square *** hash = (x << 16) | (segment.GridY + cellRadius); list = (ArrayList)_gridSquares[hash]; if (list == null) { list = new ArrayList(); _gridSquares[hash] = list; } // Make sure two organisms didn't start in the same place Debug.Assert(segment.EntryTime != 0 || !HasStartingSegments(list)); wrapper = new SegmentWrapper(segment, list); list.Add(wrapper); _sortedList.Add(wrapper); segment.CellsLeftToResolve++; } // Do left and right columns for (var y = segment.GridY - cellRadius + 1; y <= segment.GridY + cellRadius - 1; y++) { // Make a unique hash for every square in the grid var hash = ((segment.GridX - cellRadius) << 16) | y; list = (ArrayList)_gridSquares[hash]; if (list == null) { list = new ArrayList(); _gridSquares[hash] = list; } // Make sure two organisms didn't start in the same place Debug.Assert(segment.EntryTime != 0 || !HasStartingSegments(list)); wrapper = new SegmentWrapper(segment, list); list.Add(wrapper); _sortedList.Add(wrapper); segment.CellsLeftToResolve++; hash = ((segment.GridX + cellRadius) << 16) | y; list = (ArrayList)_gridSquares[hash]; if (list == null) { list = new ArrayList(); _gridSquares[hash] = list; } // Make sure two organisms didn't start in the same place Debug.Assert(segment.EntryTime != 0 || !HasStartingSegments(list)); wrapper = new SegmentWrapper(segment, list); list.Add(wrapper); _sortedList.Add(wrapper); segment.CellsLeftToResolve++; } }