Rectangle Structure that uses Float values as storage rather than integers such as the ones used in the standard XNA rectangle struct. The FRectangle structure can be used to specify texture ranges in for example the ground pallette.
Пример #1
0
 public bool Intersects(FRectangle frectangle)
 {
     return(!(frectangle.Right < this.Left ||
              frectangle.Left > this.Right ||
              frectangle.Bottom < this.Top ||
              frectangle.Top > this.Bottom));
 }
Пример #2
0
 public bool Contains(FRectangle frectangle)
 {
     return(!(frectangle.Right < this.Left || frectangle.Right > this.Right ||
              frectangle.Left < this.Left || frectangle.Left > this.Right ||
              frectangle.Top < this.Top || frectangle.Top > this.Bottom ||
              frectangle.Bottom < this.Top || frectangle.Bottom > this.Bottom));
 }
Пример #3
0
        /// <summary>
        /// Checks if Two Entities are intersecting each other assuming the specified states, gameTime and group filter.
        /// This check is actually rather ineffecient. O(n^2) time complexity. In reality though, we would be smart about
        /// what to compare - hence the group and state filters. The number of comparasins between drawables should be kept
        /// to a minimum in order to maintain performance.
        /// </summary>
        public static bool IntersectsWith(
            Entity entity1, string entity1State, string entity1Group,
            Entity entity2, string entity2State, string entity2Group, 
            GameTime gameTime
            )
        {
            HashSet<GameDrawableInstance> entity1Instances = entity1.Drawables.GetByState(entity1State);
            HashSet<GameDrawableInstance> entity2Instances = entity2.Drawables.GetByState(entity2State);

            if (entity1Instances == null || entity2Instances == null) return false;

            foreach (GameDrawableInstance instanceForEntity1 in entity1Instances)
            {
                if (entity1Group == null || instanceForEntity1._associatedGroup == entity1Group)
                {
                    Rectangle sourceRectangleEntity1 = instanceForEntity1.GetSourceRectangle(gameTime);

                    float entity1SourceWidth = sourceRectangleEntity1.Width * entity1.ScaleX;
                    float entity1SourceHeight = sourceRectangleEntity1.Height * entity1.ScaleY;

                    FRectangle absBoundingRectEntity1 = new FRectangle(
                        entity1.Pos.X - entity1SourceWidth * instanceForEntity1.Drawable.Origin.X,
                        entity1.Pos.Y - entity1SourceHeight * instanceForEntity1.Drawable.Origin.Y,
                        entity1SourceWidth,
                        entity1SourceHeight
                        );

                    foreach (GameDrawableInstance instanceForEntity2 in entity2Instances)
                    {
                        if (entity2Group == null || instanceForEntity2._associatedGroup == entity2Group)
                        {
                            Rectangle sourceRectangleEntity2 = instanceForEntity2.GetSourceRectangle(gameTime);

                            float entity2SourceWidth = sourceRectangleEntity2.Width * entity2.ScaleX;
                            float entity2SourceHeight = sourceRectangleEntity2.Height * entity2.ScaleY;

                            FRectangle absBoundingRectEntity2 = new FRectangle(
                                entity2.Pos.X - entity2SourceWidth * instanceForEntity2.Drawable.Origin.X,
                                entity2.Pos.Y - entity2SourceHeight * instanceForEntity2.Drawable.Origin.Y,
                                entity2SourceWidth,
                                entity2SourceHeight
                                );

                            // Check if the two bounding boxes intersect
                            if (absBoundingRectEntity1.Intersects(absBoundingRectEntity2))
                                return true;
                        }
                    }
                }
            }

            // No Intersection tests passed.
            return false;
        }
Пример #4
0
        internal List<List<Entity>> GetHashList(FRectangle boundingBox)
        {
            List<List<Entity>> result = new List<List<Entity>>();

            int topLeftIndex = GetIndex(boundingBox.Left, boundingBox.Top);
            int topRightIndex = GetIndex(boundingBox.Right, boundingBox.Top);
            int bottomLeftIndex = GetIndex(boundingBox.Left, boundingBox.Bottom);

            int width = topRightIndex - topLeftIndex + 1;
            int height = (bottomLeftIndex - topLeftIndex) / _boxCountY + 1;

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    int index = topLeftIndex + i + j * _boxCountX;
                    result.Add(_hashLists[index]);
                }
            }

            return result;
        }
Пример #5
0
 internal void Remove(FRectangle boundingBox, Entity entity)
 {
     foreach (List<Entity> entityList in GetHashList(boundingBox))
         entityList.Remove(entity);
 }
Пример #6
0
 public List<Entity> GetIntersectingEntities(FRectangle region)
 {
     return Collider.GetIntersectingEntites(region);
 }
Пример #7
0
        public List<Entity> GetIntersectingEntites(FRectangle pxRegion)
        {
            List<Entity> result = new List<Entity>();
            foreach (List<Entity> entities in GetHashList(pxRegion))
                foreach (Entity entity in entities)
                    if (!result.Contains(entity))
                        result.Add(entity);

            return result;
        }
Пример #8
0
 public bool Intersects(FRectangle frectangle)
 {
     return !(frectangle.Right < this.Left
               || frectangle.Left > this.Right
               || frectangle.Bottom < this.Top
               || frectangle.Top > this.Bottom );
 }
Пример #9
0
        public ViewPortInfo DrawWorldViewPort(SpriteBatch spriteBatch, Vector2 center, float zoom, Rectangle destRectangle, Color color, SamplerState samplerState, SpriteFont spriteFont=null)
        {
            ViewPortInfo viewPortInfo = new ViewPortInfo();
            {
                viewPortInfo.pxTileWidth  = (int) Math.Ceiling(Map.TileWidth * zoom);
                viewPortInfo.pxTileHeight = (int) Math.Ceiling(Map.TileHeight * zoom);

                // Note about ActualZoom Property:
                // because there is a loss of data between to conversion from Map.pxTileWidth * Zoom -> (int)
                // we need to determine what was the actual level of zoom that was applied to the tiles and use that
                // this ensures that entities that will be drawn will be placed correctly on the screen.
                viewPortInfo.ActualZoom = viewPortInfo.pxTileWidth / Map.TileWidth;

                viewPortInfo.pxWidth = destRectangle.Width / viewPortInfo.ActualZoom;
                viewPortInfo.pxHeight = destRectangle.Height / viewPortInfo.ActualZoom;

                viewPortInfo.pxTopLeftX = center.X - viewPortInfo.pxWidth / 2.0f;
                viewPortInfo.pxTopLeftY = center.Y - viewPortInfo.pxHeight / 2.0f;

                viewPortInfo.TileCountX = (int) Math.Ceiling((double)viewPortInfo.pxWidth / Map.TileWidth) + 1;
                viewPortInfo.TileCountY = (int) Math.Ceiling((double)viewPortInfo.pxHeight / Map.TileHeight) + 1;

                // Prevent the View from going outisde of the WORLD coordinates.
                if (viewPortInfo.pxTopLeftX < 0) viewPortInfo.pxTopLeftX = 0;
                if (viewPortInfo.pxTopLeftY < 0) viewPortInfo.pxTopLeftY = 0;

                if (viewPortInfo.pxTopLeftX + viewPortInfo.pxWidth >= Map.pxWidth)
                    viewPortInfo.pxTopLeftX = Map.pxWidth - viewPortInfo.pxWidth;
                if (viewPortInfo.pxTopLeftY + viewPortInfo.pxHeight >= Map.pxHeight)
                    viewPortInfo.pxTopLeftY = Map.pxHeight - viewPortInfo.pxHeight;

                // Calculate any decimal displacement required (For Positions with decimal points).
                viewPortInfo.pxDispX = viewPortInfo.pxTopLeftX - ((int)viewPortInfo.pxTopLeftX / Map.TileWidth) * Map.TileWidth;
                viewPortInfo.pxDispY = viewPortInfo.pxTopLeftY - ((int)viewPortInfo.pxTopLeftY / Map.TileHeight) * Map.TileHeight;

                viewPortInfo.pxViewPortBounds = new Rectangle(
                    (int) Math.Ceiling(viewPortInfo.pxTopLeftX),
                    (int) Math.Ceiling(viewPortInfo.pxTopLeftY),
                    (int) Math.Ceiling(viewPortInfo.pxWidth),
                    (int) Math.Ceiling(viewPortInfo.pxHeight)
                );
            }

            // RENDER THE GAME WORLD TO THE VIEWPORT RENDER TARGET
            GraphicsDevice.SetRenderTarget(_inputBuffer);
            GraphicsDevice.Clear(Map.Background);

            // DRAW THE WORLD MAP
            OverallPerformance.StartTiming("TileRenderingTime");

            // Deferred Rendering should be fine for rendering tile as long as we draw tile layers one at a time
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, samplerState, null, null);
            {
                for (int layerIndex = 0; layerIndex < Map.TileLayers.Count; layerIndex++)
                {
                    // DRAW EACH LAYER
                    TileLayer tileLayer = Map.TileLayers[layerIndex];

                    if (tileLayer.Visible)
                    {
                        Color layerColor = new Color()
                        {
                            R = tileLayer.Color.R,
                            G = tileLayer.Color.G,
                            B = tileLayer.Color.B,
                            A = (byte)(tileLayer.Color.A * tileLayer.Opacity)
                        };

                        float depth = 1 - (layerIndex / 10000.0f);

                        for (int i = 0; i < viewPortInfo.TileCountX; i++)
                        {
                            for (int j = 0; j < viewPortInfo.TileCountY; j++)
                            {
                                int tileX = (int)(i + viewPortInfo.pxTopLeftX / Map.TileWidth);
                                int tileY = (int)(j + viewPortInfo.pxTopLeftY / Map.TileHeight);

                                int tileGid = tileLayer[tileX, tileY];

                                Rectangle pxTileDestRect = new Rectangle(
                                    (int) Math.Ceiling(i * viewPortInfo.pxTileWidth - viewPortInfo.pxDispX * viewPortInfo.ActualZoom),
                                    (int) Math.Ceiling(j * viewPortInfo.pxTileHeight - viewPortInfo.pxDispY * viewPortInfo.ActualZoom),
                                    (int) viewPortInfo.pxTileWidth,
                                    (int) viewPortInfo.pxTileHeight
                                );

                                if (tileGid != 0 && tileGid != -1)   // NULL or INVALID Tile Gid is ignored
                                {
                                    Tile tile = Map.Tiles[tileGid];

                                    spriteBatch.Draw(
                                        tile.sourceTexture,
                                        pxTileDestRect,
                                        tile.SourceRectangle,
                                        layerColor,
                                        0, Vector2.Zero,
                                        SpriteEffects.None,
                                        depth
                                    );
                                }

                                // DRAW THE TILE LAYER GRID IF ENABLE
                                if (DrawingOptions.ShowTileGrid && layerIndex == Map.TileLayers.Count - 1)
                                    spriteBatch.DrawRectangle(pxTileDestRect, Color.Black, 0);
                            }
                        }
                    }
                }
            }
            spriteBatch.End();

            OverallPerformance.StopTiming("TileRenderingTime");

            // Calculate the entity Displacement caused by pxTopLeft at a global scale to prevent jittering.
            // Each entity should be displaced by the *same amount* based on the pxTopLeftX/Y values
            // this is to prevent entities 'jittering on the screen' when moving the camera.
            float globalDispX = (int) Math.Ceiling(viewPortInfo.pxTopLeftX * viewPortInfo.ActualZoom);
            float globalDispY = (int) Math.Ceiling(viewPortInfo.pxTopLeftY * viewPortInfo.ActualZoom);

            // DRAW VISIBLE REGISTERED ENTITIES
            OverallPerformance.RestartTiming("TotalEntityRenderTime");
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, samplerState, null, null);
            {
                EntitiesOnScreen = Collider.GetIntersectingEntites(new FRectangle(viewPortInfo.pxViewPortBounds));

                // DRAW EACH ENTITIY THAT IS WITHIN THE SCREENS VIEWPORT
                foreach (Entity entity in EntitiesOnScreen)
                {
                    EntityRenderPerformance.RestartTiming(entity.Name);

                    if (!entity.Visible) continue;
                    entity.IsOnScreen = true;

                    // Determine the absolute position on the screen for entity position and the bounding box.
                    Vector2 pxAbsEntityPos = new Vector2(
                        entity.Pos.X * viewPortInfo.ActualZoom - globalDispX,
                        entity.Pos.Y * viewPortInfo.ActualZoom - globalDispY
                    );

                    FRectangle pxAbsBoundingBox = new FRectangle(
                        entity.CurrentBoundingBox.X * viewPortInfo.ActualZoom - globalDispX,
                        entity.CurrentBoundingBox.Y * viewPortInfo.ActualZoom - globalDispY,
                        entity.CurrentBoundingBox.Width * viewPortInfo.ActualZoom,
                        entity.CurrentBoundingBox.Height * viewPortInfo.ActualZoom
                    );

                    // DRAW ENTITY BOUNDING BOXES IF ENABLED
                    if (DrawingOptions.ShowBoundingBoxes)
                    {
                        spriteBatch.DrawRectangle(pxAbsBoundingBox.ToRectangle(), Color.Red, 0.0001f);
                        SpriteBatchExtensions.DrawCross(
                            spriteBatch,
                            new Vector2(
                                (int) Math.Ceiling(pxAbsEntityPos.X),
                                (int) Math.Ceiling(pxAbsEntityPos.Y)
                            ),
                            13, Color.Black, 0f);
                    }

                    // DRAW ENTITY DETAILS IF ENABLED (ENTITY DEBUG INFO)
                    if (DrawingOptions.ShowEntityDebugInfo)
                    {
                        SpriteBatchExtensions.DrawMultiLineString(
                            spriteBatch,
                            spriteFont,
                            entity.GetDebugInfo(),
                            (int) entity.CurrentBoundingBox.Width * 2,
                            4,
                            new Vector2(
                                pxAbsBoundingBox.X + pxAbsBoundingBox.Width/2,
                                pxAbsBoundingBox.Y + pxAbsBoundingBox.Height/2
                                ),
                            Color.Purple);
                    }

                    // DRAW EVERY GAMEDRAWABLE INSTANCE CURRENTLY ACTIVE IN THE ENTITIES DRAWABLE SET.
                    HashSet<GameDrawableInstance> drawableInstances = entity.Drawables.GetByState(entity.CurrentDrawableState);

                    if (drawableInstances != null)
                    {
                        foreach (GameDrawableInstance drawable in drawableInstances)
                        {
                            if (!drawable.Visible) continue;

                            // The relative position of the object should always be (X,Y) - (globalDispX, globalDispY). globalDispX and globalDispY
                            // are based on viewPortInfo.TopLeftX and viewPortInfo.TopLeftY. viewPortInfo.TopLeftX and viewPortInfo.TopLeftY have
                            // already been corrected in terms of the bounds of the WORLD map coordinates. This allows for panning at the edges.
                            Rectangle pxCurrentFrame = drawable.GetSourceRectangle(LastUpdateTime);

                            int pxObjectWidth = (int)Math.Ceiling(pxCurrentFrame.Width * entity.ScaleX * viewPortInfo.ActualZoom);
                            int pxObjectHeight = (int)Math.Ceiling(pxCurrentFrame.Height * entity.ScaleY * viewPortInfo.ActualZoom);

                            // Draw the Object based on the current Frame dimensions and the specified Object Width Height values.
                            Rectangle objectDestRect = new Rectangle(
                                    (int)Math.Ceiling(pxAbsEntityPos.X) + (int)Math.Ceiling(drawable.Offset.X * viewPortInfo.ActualZoom),
                                    (int)Math.Ceiling(pxAbsEntityPos.Y) + (int)Math.Ceiling(drawable.Offset.Y * viewPortInfo.ActualZoom),
                                    pxObjectWidth,
                                    pxObjectHeight
                            );

                            Vector2 drawableOrigin = new Vector2(
                                (float)Math.Ceiling(drawable.Drawable.Origin.X * pxCurrentFrame.Width),
                                (float)Math.Ceiling(drawable.Drawable.Origin.Y * pxCurrentFrame.Height)
                                );

                            Color drawableColor = new Color()
                            {
                                R = drawable.Color.R,
                                G = drawable.Color.G,
                                B = drawable.Color.B,
                                A = (byte)(drawable.Color.A * entity.Opacity)
                            };

                            // Layer depth should depend how far down the object is on the map (Relative to Y).
                            // Important to also take into account the animation layers for the entity.
                            float layerDepth = Math.Min(0.99f, 1 / (entity.Pos.Y + ((float)drawable.Layer / Map.pxHeight)));

                            // FINALLY ... DRAW
                            spriteBatch.Draw(
                                drawable.GetSourceTexture(LastUpdateTime),
                                objectDestRect,
                                pxCurrentFrame,
                                drawableColor,
                                drawable.Rotation,
                                drawableOrigin,
                                drawable.SpriteEffects,
                                layerDepth);

                            // DRAW BOUNDING BOXES OF EACH INDIVIDUAL DRAWABLE COMPONENT
                            if (DrawingOptions.ShowDrawableComponents)
                            {
                                Rectangle drawableComponentRect = new Rectangle(
                                    (int)Math.Floor(objectDestRect.X - objectDestRect.Width * drawable.Drawable.Origin.X),
                                    (int)Math.Floor(objectDestRect.Y - objectDestRect.Height * drawable.Drawable.Origin.Y),
                                    objectDestRect.Width, objectDestRect.Height);

                                SpriteBatchExtensions.DrawRectangle(
                                    spriteBatch, drawableComponentRect, Color.Blue, 0);
                            }
                        }
                    }

                    EntityRenderPerformance.StopTiming(entity.Name);
                }
            }
            spriteBatch.End();
            OverallPerformance.StopTiming("TotalEntityRenderTime");

            // APPLY GAME SHADERS TO THE RESULTANT IMAGE
            OverallPerformance.RestartTiming("TotalPostGameShaderRenderTime");
            foreach(PostGameShader postGameShader in GameShaders)
            {
                if (postGameShader.Enabled)
                {
                    postGameShader.ApplyShader(spriteBatch, viewPortInfo, LastUpdateTime, _inputBuffer, _outputBuffer);

                    // Swap buffers after each render.
                    _dummyBuffer = _inputBuffer;
                    _inputBuffer = _outputBuffer;
                    _outputBuffer = _dummyBuffer;
                }
            }
            OverallPerformance.StopTiming("TotalPostGameShaderRenderTime");

            // DRAW COLLIDER DEBUG INFORMATION IF ENABLED
            if (DrawingOptions.ShowColliderDebugInfo)
            {
                spriteBatch.Begin();
                Collider.DrawDebugInfo(viewPortInfo, spriteBatch, destRectangle, spriteFont, globalDispX, globalDispY);
                spriteBatch.End();
            }

            // DRAW THE VIEWPORT TO THE STANDARD SCREEN
            GraphicsDevice.SetRenderTarget(null);
            spriteBatch.Begin();
            {
                spriteBatch.Draw(_inputBuffer, destRectangle, color);
            }
            spriteBatch.End();

            return viewPortInfo;
        }
Пример #10
0
        internal void GetEntities(FRectangle? pxRegion, ref List<Entity> result)
        {
            if (Entities.Count > 0)
            {
                foreach (Entity entity in Entities)
                    if (!result.Contains(entity))           // TODO: This needs to be removed. It is slow and should not be here
                        result.Add(entity);
            }
            else
            {
                if (IsLeafNode) return;

                if (pxRegion == null || ChildNode1.Intersects(pxRegion.Value)) ChildNode1.GetEntities(pxRegion, ref result);
                if (pxRegion == null || ChildNode2.Intersects(pxRegion.Value)) ChildNode2.GetEntities(pxRegion, ref result);
                if (pxRegion == null || ChildNode3.Intersects(pxRegion.Value)) ChildNode3.GetEntities(pxRegion, ref result);
                if (pxRegion == null || ChildNode4.Intersects(pxRegion.Value)) ChildNode4.GetEntities(pxRegion, ref result);
            }
        }
Пример #11
0
 public bool Contains(FRectangle frectangle)
 {
     return !(frectangle.Right < this.Left || frectangle.Right > this.Right
              || frectangle.Left < this.Left || frectangle.Left > this.Right
              || frectangle.Top < this.Top || frectangle.Top > this.Bottom
              || frectangle.Bottom < this.Top || frectangle.Bottom > this.Bottom);
 }
Пример #12
0
        public void Remove(Entity Entity, FRectangle? pxBoundingBox)
        {
            List<QuadTreeNode> associations = new List<QuadTreeNode>();
            GetAssociatedNodes(Entity, pxBoundingBox, ref associations);

            foreach (QuadTreeNode node in associations)
            {
                node.Entities.Remove(Entity);
                node.Validate(this);
            }
        }
Пример #13
0
 public bool Intersects(FRectangle pxBoundingBox)
 {
     return pxBounds.Intersects(pxBoundingBox);
 }
Пример #14
0
        // If pxBoundingBox is null, it will search everywhere
        public void GetAssociatedNodes(Entity entity, FRectangle? pxBoundingBox, ref List<QuadTreeNode> result)
        {
            if (IsLeafNode)
            {
                if (Entities.Contains(entity)) result.Add(this);
                return;
            }

            if (pxBoundingBox == null || ChildNode1.Intersects(pxBoundingBox.Value)) ChildNode1.GetAssociatedNodes(entity, pxBoundingBox, ref result);
            if (pxBoundingBox == null || ChildNode2.Intersects(pxBoundingBox.Value)) ChildNode2.GetAssociatedNodes(entity, pxBoundingBox, ref result);
            if (pxBoundingBox == null || ChildNode3.Intersects(pxBoundingBox.Value)) ChildNode3.GetAssociatedNodes(entity, pxBoundingBox, ref result);
            if (pxBoundingBox == null || ChildNode4.Intersects(pxBoundingBox.Value)) ChildNode4.GetAssociatedNodes(entity, pxBoundingBox, ref result);
        }
Пример #15
0
 public bool Contains(FRectangle pxBoundingBox)
 {
     return pxBounds.Contains(pxBoundingBox);
 }
Пример #16
0
        public static bool IntersectsWith(Entity entity, string entityState, string entityGroup, FRectangle bounds, GameTime gameTime)
        {
            HashSet<DrawableInstance> entityInstances = entity.Drawables.GetByState(entityState);

            if (entityInstances == null) return false;

            foreach (DrawableInstance instance in entityInstances)
            {
                if (entityGroup == null || instance._associatedGroup == entityGroup)
                {
                    float entitySourceWidth = instance.GetWidth(gameTime) * entity.ScaleX;
                    float entitySourceHeight = instance.GetHeight(gameTime) * entity.ScaleY;

                    FRectangle absBoundingBox = new FRectangle(
                        entity.Pos.X - entitySourceWidth * instance.Drawable.Origin.X,
                        entity.Pos.Y - entitySourceHeight * instance.Drawable.Origin.Y,
                        entitySourceWidth,
                        entitySourceHeight
                        );

                    if (bounds.Intersects(absBoundingBox))
                        return true;
                }
            }

            // No intersection tests passed.
            return false;
        }