Пример #1
0
        /// <summary>
        ///     Generates an OctTree used to improve collision processing.
        /// </summary>
        /// <returns>Newly generated OctTree.</returns>
        private static ArrayList[,] GenerateOctTree()
        {
            // Work out a full-size bounding box that encloses all polygons.
            float minX = 0, minY = 0, maxX = 0, maxY = 0;
            foreach (CollisionPolygon prePolygon in _polygonList)
            {
                if (prePolygon.Transformation.X < minX) minX = prePolygon.Transformation.X;
                if (prePolygon.Transformation.Y < minY) minY = prePolygon.Transformation.Y;
                if (prePolygon.Transformation.X + prePolygon.BoundingWidth > maxX) maxX = prePolygon.Transformation.X + prePolygon.BoundingWidth;
                if (prePolygon.Transformation.Y + prePolygon.BoundingHeight > maxY) maxY = prePolygon.Transformation.Y + prePolygon.BoundingHeight;
            }

            int octTreeCellWidth = 128;
            int octTreeCellHeight = 128;
            int octTreeXCells = (int)Math.Ceiling((maxX - minX) / (float)octTreeCellWidth);
            int octTreeYCells = (int)Math.Ceiling((maxY - minY) / (float)octTreeCellHeight);

            if (_octTree == null || octTreeXCells != _octTreeXCells || octTreeYCells != _octTreeYCells)
            {
                // Generate an Oct-Tree.
                _octTreeXCells = octTreeXCells;
                _octTreeYCells = octTreeYCells;
                _octTree = new ArrayList[octTreeXCells, octTreeYCells];
                for (int x = 0; x < octTreeXCells; x++)
                    for (int y = 0; y < octTreeYCells; y++)
                        _octTree[x, y] = new ArrayList();

                // Generate collision rectangles.
                _octTreeCollisionRectangles = new CollisionRectangle[octTreeXCells, octTreeYCells];
                for (int x = 0; x < octTreeXCells; x++)
                    for (int y = 0; y < octTreeYCells; y++)
                        _octTreeCollisionRectangles[x, y] = new CollisionRectangle(new Transformation(minX + (x * octTreeCellWidth), minY + (y * octTreeCellHeight), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f), octTreeCellWidth, octTreeCellHeight);

                // Place entities into Oct-Tree cells.
                for (int x = 0; x < octTreeXCells; x++)
                    for (int y = 0; y < octTreeYCells; y++)
                    {
                        foreach (CollisionPolygon prePolygon in _polygonList)
                        {
                            if (_octTreeCollisionRectangles[x, y].HitTest(prePolygon) == true)
                                _octTree[x, y].Add(prePolygon);
                        }
                    }
            }
            else
            {
                // Have any polygons moved? If so we need to update the cells they are in.
                foreach (CollisionPolygon polygon in _polygonList)
                {
                    if ((!((polygon.PreviousTransformationValid == false ||
                        ((polygon.Transformation.X - polygon.PreviousTransformation.X == 0) &&
                        (polygon.Transformation.Y - polygon.PreviousTransformation.Y == 0))) && polygon.FrameCount > 0)))// || polygon.BoundingChanged == true)
                    {
                        _octTreeRemovals.Add(polygon);
                        _octTreeAdditions.Add(polygon);
                    }
                }
            }

            // Remove superflous ones.
            if (_octTreeRemovals.Count != 0)
            {
                foreach (CollisionPolygon polygon in _octTreeRemovals)
                {
                    for (int x = 0; x < octTreeXCells; x++)
                        for (int y = 0; y < octTreeYCells; y++)
                            _octTree[x, y].Remove(polygon);
                }
                _octTreeRemovals.Clear();
            }

            // Add aditional ones.
            if (_octTreeAdditions.Count != 0)
            {
                foreach (CollisionPolygon polygon in _octTreeAdditions)
                {
                    for (int x = 0; x < octTreeXCells; x++)
                        for (int y = 0; y < octTreeYCells; y++)
                        {
                            if (_octTreeCollisionRectangles[x, y].HitTest(polygon) == true)
                            {
                                _octTree[x, y].Add(polygon);
                            }
                        }
                }
                _octTreeAdditions.Clear();
            }

            return _octTree;
        }
Пример #2
0
        /// <summary>
        ///     Attempts to respond to a collision by moving this rectangle out
        ///     of the given rectangle.
        /// </summary>
        /// <param name="rectangle">Rectangle that this rectangle is currently penetrating.</param>
        public void RespondToRectangleCollision(CollisionRectangle rectangle)
        {
            // Truncate the positions of the entitys as decimal places tend
            // to f**k up collision response.

            _transformation.X = (float)Math.Truncate(_transformation.X);
            _transformation.Y = (float)Math.Truncate(_transformation.Y);
            rectangle._transformation.X = (float)Math.Truncate(rectangle._transformation.X);
            rectangle._transformation.Y = (float)Math.Truncate(rectangle._transformation.Y);

            // Really crude form of SAT collision response.
            // Probably a good idea to clean this up a bit, possibly implement
            // vector projection as well, to remove the if blocks.

            float rectangleWidth = rectangle._width * Math.Abs(rectangle._transformation.ScaleX), rectangleHeight = rectangle._height * Math.Abs(rectangle._transformation.ScaleY);
            float rectangleCenterX = rectangle._transformation.X + (rectangleWidth / 2.0f), rectangleCenterY = rectangle._transformation.Y + (rectangleHeight / 2.0f);
            float thisWidth = _width * Math.Abs(_transformation.ScaleX), thisHeight = _height * Math.Abs(_transformation.ScaleY);
            float thisCenterX = _transformation.X + (thisWidth / 2.0f), thisCenterY = _transformation.Y + (thisHeight / 2.0f);
            float rectangleVertexX = 0, rectangleVertexY = 0;
            float thisVertexX = 0, thisVertexY = 0;

            if (thisCenterX > rectangleCenterX)
                if (thisCenterY > rectangleCenterY)
                {
                    // Were in the bottom-right corner of the rectangle.
                    rectangleVertexX = rectangle._transformation.X + rectangleWidth;
                    rectangleVertexY = rectangle._transformation.Y + rectangleHeight;
                    thisVertexX = _transformation.X;
                    thisVertexY = _transformation.Y;
                }
                else
                {
                    // Were in the top-right corner of the rectangle.
                    rectangleVertexX = rectangle._transformation.X + rectangleWidth;
                    rectangleVertexY = rectangle._transformation.Y;
                    thisVertexX = _transformation.X;
                    thisVertexY = _transformation.Y + thisHeight;
                }
            else
                if (thisCenterY > rectangleCenterY)
                {
                    // Were in the bottom-left corner of the rectangle.
                    rectangleVertexX = rectangle._transformation.X;
                    rectangleVertexY = rectangle._transformation.Y + rectangleHeight;
                    thisVertexX = _transformation.X + thisWidth;
                    thisVertexY = _transformation.Y;
                }
                else
                {
                    // Were in the top-left corner of the rectangle.
                    rectangleVertexX = rectangle._transformation.X;
                    rectangleVertexY = rectangle._transformation.Y;
                    thisVertexX = _transformation.X + thisWidth;
                    thisVertexY = _transformation.Y + thisHeight;
                }

            float xDifference = thisVertexX - rectangleVertexX;
            float yDifference = thisVertexY - rectangleVertexY;
            if (Math.Abs(xDifference) > Math.Abs(yDifference))
                _transformation.Y -= yDifference;
            else
                _transformation.X -= xDifference;
        }
Пример #3
0
        /// <summary>
        ///     Checks for and returns the polygon at the given point.
        /// </summary>
        /// <param name="x">Position on the x-axis.</param>
        /// <param name="y">Position on the y-axis.</param>
        /// <returns>Null if no polygon at given point, else true.</returns>
        public static CollisionPolygon PolygonAtPoint(int x, int y)
        {
            CollisionPolygon aPolygon = new CollisionRectangle(new Transformation(x, y, 0, 0, 0, 0, 1, 1, 1), 1, 1);

            foreach (CollisionPolygon polygon in _polygonList)
                if (aPolygon != polygon && polygon.HitTest(aPolygon) == true && polygon.Solid == true)
                    return polygon;

            return null;
        }
Пример #4
0
 public void EntityHitTestB(ScriptThread thread)
 {
     EntityNode entitya = ((NativeObject)thread.GetObjectParameter(0)).Object as EntityNode;
     if (entitya == null)
     {
         DebugLogger.WriteLog((thread.Process.Url != null && thread.Process.Url != "" ? thread.Process.Url : "A script") + " called EntityHitTest with an invalid object.", LogAlertLevel.Error);
         return;
     }
     CollisionRectangle rect = new CollisionRectangle(new Transformation(thread.GetIntegerParameter(1), thread.GetIntegerParameter(2), 0, 0, 0, 0, 1, 1, 1), thread.GetIntegerParameter(3), thread.GetIntegerParameter(4));
     rect.Layers = entitya.CollisionPolygon.Layers;
     thread.SetReturnValue(entitya.CollisionPolygon.HitTest(rect));
 }