/// <summary> /// Reads data from the world grid. Not done in the constructor to allow callers to subscribe to /// the events that will be fired. /// </summary> /// <param name="position"> The position. </param> public void Initialize(GridCoordinate position) { _currentPosition = position; _viewCurrentPosition = ConvertToGridItemIndex(position); InitializeUnits(); }
/// <summary> /// Converts the given grid coordinate into a an index that can be used to get the data in /// <see cref="_visibleGridItems"/>. /// </summary> /// <remarks> /// Multiple GridCoordinates map to the same ArrayIndex, so this is technically an irreversible /// operation. However, provided we always remain within the correct GridCoordinates (e.g. always /// use grid coordinates that we generate or which are validated first), we should never really /// have a situation where a conversion to an array index and back results in a different /// coordinate. /// </remarks> /// <param name="coordinate"> The coordinate. </param> /// <returns> The given data converted to a grid item index. </returns> private Array2DIndex ConvertToGridItemIndex(GridCoordinate coordinate) { var correctedX = MathUtils.PositiveRemainder(coordinate.X, _visibleGridItems.Width); var correctedY = MathUtils.PositiveRemainder(coordinate.Y, _visibleGridItems.Height); var arrayIndex = new Array2DIndex(correctedX, correctedY); return(arrayIndex); }
/// <summary> Changes the position being observed. </summary> public void Recenter(GridCoordinate center) { var originalPosition = _currentPosition; _currentPosition = center; _viewCurrentPosition = ConvertToGridItemIndex(_currentPosition); UpdateChangedUnits(originalPosition); }
/// <summary> Updates the data at the specified index inside the grid. </summary> /// <param name="index"> Zero-based index of the. </param> /// <param name="data"> The grid data to store. </param> /// <param name="position"> The coordinate of the original GridItem where the data was retrieved /// from. </param> /// <param name="chunk"></param> private void UpdateData(Array2DIndex index, GridItem data, GridCoordinate position, Chunk chunk) { var newData = new SliceUnitData <T>(chunk, position, data, default(T)); var rawIndex = _visibleGridItems.CalculateRawArrayIndex(index); var oldData = _visibleGridItems.Data[rawIndex]; _visibleGridItems.Data[rawIndex] = newData; DataChanged?.Invoke(oldData, ref _visibleGridItems.Data[rawIndex]); MarkChunkChanged(oldData.Chunk, chunk); }
/// <summary> /// Converts an array index into the expected grid coordinate for the given index. /// </summary> /// <param name="arrayIndex"> Zero-based index of the array. </param> /// <returns> The given data converted to a grid coordinate. </returns> private GridCoordinate ConvertToGridCoordinate(Array2DIndex arrayIndex) { var difViewX = _viewCurrentPosition.X - arrayIndex.X; var signX = GetSign(difViewX); // Normalize the offset from the "current" view position. // // This explanation just talks about X, the same theory holds for Y. Imagine a number line // ranging from 0 to maxViewX). // // If the current position is on the right (so it's position is maxViewX), then the very left // position (position 0) of the view really just represents one world unit to the right of the // current position. If we simply subtracted these two positions, however, it would be // reported it as a difference of -ViewWidth units away We want to convert it to a difference // of (1). // // We know we have to do convert values if it's more than half the size away (that's the only // time that wrapping occurs when putting the values into the view). The conversion is fairly // straight forward when given examples: // - When we're `maxViewX` view units away, we're really only 1 world unit away. // - When we're `maxViewX - 1` units away we're really only 2 world units away. // - When we're `maxViewX - N` units away, we're really only N world units away. // // The pattern to find N (the world units away) is to take `ViewWidth` and "subtract" // `(maxViewX - N)`. `maxViewX - N` happens to be diffViewX, so then we just have to "subtract" // it from `ViewWidth`. "subtract" is in quotes because actually, when the difference is // negative, we want to add `ViewWidth` (otherwise we end up in very negative territory). So we // add when `maxViewX - N` is negative, subtract when `maxViewX - N` is positive. var offsetX = Math.Abs(difViewX) > _numUnitsWideHalfThreshold ? difViewX + -signX * _visibleGridItems.Width : difViewX; // all of the above but now for Y var difViewY = _viewCurrentPosition.Y - arrayIndex.Y; var signY = difViewY >= 0 ? 1 : -1; var offsetY = Math.Abs(difViewY) > _numUnitsHighHalfThreshold ? difViewY + -signY * _visibleGridItems.Height : difViewY; var gridPosition = _currentPosition.OffsetBy(-offsetX, -offsetY); ValidateConversion(gridPosition, arrayIndex); return(gridPosition); }
/// <summary> Initialize each grid unit. </summary> private void InitializeUnits() { for (var y = 0; y < _visibleGridItems.Height; y++) { for (var x = 0; x < _visibleGridItems.Width; x++) { var index = new Array2DIndex(x, y); var coordinate = ConvertToGridCoordinate(index); var subCoordinates = coordinate.AsSubCoordinates(); if (_worldGrid.IsValid(subCoordinates.ChunkCoordinate)) { var(chunk, data) = _worldGrid.GetChunkAndCellData(subCoordinates); UpdateData(index, data, coordinate, chunk, GridItemPropertyChange.All); } } } }
/// <summary> /// Checks the array index/position to verify that it has the correct position information and if /// it does not, re-reads the data from the world and updates the data. /// </summary> private void Invalidate(Array2DIndex index, GridCoordinate coordinate, bool bypassSamePositionCheck, GridItemPropertyChange changeType) { var existingData = _visibleGridItems[index]; if (!bypassSamePositionCheck && existingData.Position == coordinate) { return; } var subCoordinate = coordinate.AsSubCoordinates(); if (!_worldGrid.IsValid(subCoordinate.ChunkCoordinate)) { return; } var(chunk, data) = _worldGrid.GetChunkAndCellData(subCoordinate); UpdateData(index, data, coordinate, chunk, changeType); }
/// <summary> Initialize each grid unit. </summary> private void InitializeUnits() { for (var y = 0; y < _visibleGridItems.Height; y++) { for (var x = 0; x < _visibleGridItems.Width; x++) { var index = new Array2DIndex(x, y); var coordinate = ConvertToGridCoordinate(index); var chunkCoordinate = coordinate.ChunkCoordinate; if (_worldGrid.IsValid(chunkCoordinate)) { var chunk = _worldGrid[chunkCoordinate]; var data = chunk[coordinate.InnerChunkGridCoordinate]; UpdateData(index, data, coordinate, chunk); } } } }
/// <summary> /// Checks the array index/position to verify that it has the correct position information and if /// it does not, re-reads the data from the world and updates the data. /// </summary> /// <param name="index"> The index position to update. </param> /// <param name="coordinate"> The coordinate representing the position to update. </param> private void Invalidate(Array2DIndex index, GridCoordinate coordinate, bool bypassSamePositionCheck = false) { var existingData = _visibleGridItems[index]; if (!bypassSamePositionCheck && existingData.Position == coordinate) { return; } var chunkCoordinate = coordinate.ChunkCoordinate; if (!_worldGrid.IsValid(chunkCoordinate)) { return; } var chunk = _worldGrid[chunkCoordinate]; var data = chunk[coordinate.InnerChunkGridCoordinate]; UpdateData(index, data, coordinate, chunk); }
private void ValidateConversion(GridCoordinate gridPosition, Array2DIndex arrayIndex) { var worked = ConvertToGridItemIndex(gridPosition).X == arrayIndex.X && ConvertToGridItemIndex(gridPosition).Y == arrayIndex.Y; if (worked) { return; } // to aid in debugging worked = ConvertToGridItemIndex(gridPosition).X == arrayIndex.X && ConvertToGridItemIndex(gridPosition).Y == arrayIndex.Y; var message = new StringBuilder(); message.AppendFormat("Array Index ({0}) was converted into Grid Position ({1})", arrayIndex, gridPosition); message.AppendFormat("But we expected ({0},{1})", ConvertToGridItemIndex(gridPosition).X, ConvertToGridItemIndex(gridPosition).Y); Debug.WriteLine(message); }
/// <summary> Updates the data at the specified index inside the grid. </summary> /// <param name="index"> Zero-based index of the. </param> /// <param name="data"> The grid data to store. </param> /// <param name="position"> The coordinate of the original GridItem where the data was retrieved /// from. </param> /// <param name="chunk"></param> /// <param name="changeType"></param> private void UpdateData(Array2DIndex index, GridItem data, GridCoordinate position, Chunk chunk, GridItemPropertyChange changeType) { var newData = new SliceUnitData <T>(chunk, position, data, default(T)); var rawIndex = _visibleGridItems.CalculateRawArrayIndex(index); ref var slot = ref _visibleGridItems.Data[rawIndex];
private void Invalidate(Array2DIndex index, GridCoordinate coordinate) => Invalidate(index, coordinate, bypassSamePositionCheck: false, changeType: GridItemPropertyChange.All);
/// <summary> /// Checks the array index/position to verify that it has the correct position information and if /// it does not, re-reads the data from the world and updates the data. /// </summary> /// <param name="index"> The index position to update. </param> private void InvalidateIndex(Array2DIndex index) { Invalidate(index, ConvertToGridCoordinate(index)); }