/// <summary> Initializes the given chunk. </summary>
        public static void InitializeChunk(Chunk chunk, IPerlinNoiseProvider noiseProvider)
        {
            var position = chunk.Position;

            for (int y = 0; y < Chunk.NumberOfGridItemsHigh; y++)
            {
                for (int x = 0; x < Chunk.NumberOfGridItemsWide; x++)
                {
                    var gridPosition = new GridCoordinate(position, new InnerChunkGridCoordinate(x, y));
                    var gridItem     = GetGridItemAt(gridPosition, chunk, noiseProvider);

                    chunk[gridPosition.InnerChunkGridCoordinate] = gridItem;
                }
            }
        }
        /// <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 static GridItem GetGridItemAt(GridCoordinate gridPosition, Chunk chunk, IPerlinNoiseProvider noiseProvider)
        {
            // TODO UNITY
            // TODO load this from somewhere else
            var tileValue = noiseProvider.GetNoise(gridPosition.X / 10f, gridPosition.Y / 10f);

            // TODO UNITY
            // TODO remove random call
            byte     variant = (byte)random.Next(0, 4);
            GridItem gridItem;

            if (tileValue > 0.7f)
            {
                gridItem = new GridItem(TileType.Water, variant);
            }
            else if (tileValue < 0.3f)
            {
                gridItem = new GridItem(TileType.Hill, variant);
            }
            else
            {
                gridItem = new GridItem(TileType.Path, variant);
            }

            var buildingValue = noiseProvider.GetNoise(-gridPosition.X / 8f, gridPosition.Y / 8f);

            if (gridPosition.X % 2 == 0 &&
                gridPosition.Y % 2 == 0 &&
                buildingValue > 0.85f &&
                gridItem.Type != TileType.Water)
            {
                // TODO UNITY
                //gridItem.BuildingType = BuildingType.TreeStump;
                //gridItem.BuildingInstance = 1;
                //gridItem.Entity = chunk.Storage.CreateEntity(TreeTrunk.Instance);
            }

            return(gridItem);
        }
        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);
        }
 public bool Equals(GridCoordinate other)
 {
     return(X == other.X && Y == other.Y);
 }
 private void HandleChunkItemChanged(Chunk chunk, GridCoordinate coordinate, GridItem oldvalue, GridItem newvalue)
 {
     Invalidate(ConvertToGridItemIndex(coordinate), coordinate, bypassSamePositionCheck: true);
 }
 /// <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="coordinate"> The coordinate representing the position to update. </param>
 private void InvalidatePosition(GridCoordinate coordinate)
 {
     Validate(coordinate);
     Invalidate(ConvertToGridItemIndex(coordinate), coordinate);
 }
        /// <summary> Updates the cells that have changed because the target has changed. </summary>
        /// <param name="previousCoordinate"> The last position we were at. </param>
        private void UpdateChangedUnits(GridCoordinate previousCoordinate)
        {
            var xDiff = _currentPosition.X - previousCoordinate.X;
            var yDiff = _currentPosition.Y - previousCoordinate.Y;

            if (xDiff == 0 && yDiff == 0)
            {
                return;
            }

            if (Math.Abs(xDiff) >= _visibleGridItems.Width ||
                Math.Abs(yDiff) >= _visibleGridItems.Height
                )
            {
                // if we ever move more units than we have, then just invalidate the whole thing.
                UpdateAllUnits();
                return;
            }

            // if we're at (x,y) from (x-1, y-1), then (x+halfWidth, y+halfHeight) just came into view (of
            // course if we just came from (x+1, y+1), then (x-halfWidth, y-halfWidth) just came into view.

            // This used to be `amountToOffsetX = MathUtils.Signed(xDiff, _numUnitsWideHalfThreshold)` but
            // then when we moved right it would update the top-right corner one higher than when we moved
            // up. I'm not sure why we need to invalidate one higher when moving in the positive direction
            // but it seems to work.
            //
            // My current theory as to why is that it has something to do with one of the conversion
            // algorithms preferring the positive direction over the negative.
            var amountToOffsetX = xDiff > 0 ? _numUnitsWideHalfThreshold + 1 : -_numUnitsWideHalfThreshold;
            var amountToOffsetY = yDiff > 0 ? _numUnitsHighHalfThreshold + 1 : -_numUnitsHighHalfThreshold;

            var start = previousCoordinate.OffsetBy(amountToOffsetX, amountToOffsetY);
            var end   = _currentPosition.OffsetBy(amountToOffsetX, amountToOffsetY);

            var startColumn = start.X;
            var endColumn   = end.X;

            // make sure our for loop will work :: )
            if (startColumn > endColumn)
            {
                MathUtils.Swap(ref startColumn, ref endColumn);
            }

            var startRow = start.Y;
            var endRow   = end.Y;

            if (startRow > endRow)
            {
                MathUtils.Swap(ref startRow, ref endRow);
            }

            // OPTIMIZATION 1 - Instead of using PositiveRemainder, we could just have loop through twice
            // (when needed) because we know that we can only have to dis-jointed sets of rows[/columns]
            //
            // OPTIMIZATION 2 - We're currently always hitting the area where the rows/columns overlap
            // twice.  We could optimize this out (especially if/when we do #1 above).

            // update the rows that need to be updated
            for (var y = startRow; y < endRow; y++)
            {
                for (var x = _currentPosition.X - _numUnitsWideHalfThreshold;
                     x <= _currentPosition.X + _numUnitsWideHalfThreshold;
                     x++)
                {
                    InvalidatePosition(new GridCoordinate(x, y));
                }
            }

            // update that columns that need to be updated
            for (var y = _currentPosition.Y - _numUnitsHighHalfThreshold;
                 y <= _currentPosition.Y + _numUnitsHighHalfThreshold;
                 y++)
            {
                for (var x = startColumn; x < endColumn; x++)
                {
                    InvalidatePosition(new GridCoordinate(x, y));
                }
            }
        }