/// <summary>
        /// Initialize the singleton.  Call before first use.
        /// </summary>
        /// <param name="device">The initialized graphics device.  Used to calculate screen position.</param>
        public void Initialize(GraphicsDevice device)
        {
            mTransform      = Matrix.Identity;
            mTargetPosition = new Vector2(device.Viewport.Width * 0.5f, device.Viewport.Height * 0.5f);
            mLastPosition   = new Vector2();
            mCurBlendFrames = 0;

            mBlendFrames  = 10;
            mScreenCenter = Matrix.CreateTranslation(device.Viewport.Width * 0.5f, device.Viewport.Height * 0.5f, 0);
#if SMALL_WINDOW
            mZoomAmount = 4.0f;
#else
            mZoomAmount = 8.0f;
#endif

            mTransform =
                Matrix.CreateTranslation(-new Vector3(0f, 0f, 0.0f)) *
                //Matrix.CreateRotationZ(Rotation) *
                Matrix.CreateScale(new Vector3(mZoomAmount)) *
                mScreenCenter;

            mTransformUI = Matrix.CreateScale(new Vector3(mZoomAmount));

            mViewRectangle = new Math.Rectangle();
        }
Example #2
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="clusterSize">How many tiles along each wall of a Cluster. Assumes square tiles.</param>
        /// <param name="tileWidth">The width in pixels of a single Tile in this Level.</param>
        /// <param name="tileHeight">The height in pixels of a single Tile in this Level.</param>
        public Cluster(Int32 clusterSize, Int32 tileWidth, Int32 tileHeight)
            : base()
        {
            mClusterSize = clusterSize;

            mTileDimensions = new Point(tileWidth, tileHeight);

            mBounds = new Math.Rectangle(tileWidth * clusterSize, tileHeight * clusterSize);

            mNeighbours = new Cluster[(Int32)AdjacentClusterDirections.COUNT];
        }
Example #3
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="clusterSize">How many tiles along each wall of a Cluster. Assumes square tiles.</param>
        /// <param name="tileWidth">The width in pixels of a single Tile in this Level.</param>
        /// <param name="tileHeight">The height in pixels of a single Tile in this Level.</param>
        public Cluster(Int32 clusterSize, Int32 tileWidth, Int32 tileHeight)
            : base()
        {
            mClusterSize = clusterSize;

            mTileDimensions = new Point(tileWidth, tileHeight);

            mBounds = new Math.Rectangle(tileWidth * clusterSize, tileHeight * clusterSize);

            mNeighbours = new Cluster[Enum.GetNames(typeof(AdjacentClusterDirections)).Length];
        }
Example #4
0
        /// <summary>
        /// Since this Graph is organized into clusters, we can severly limit the amount of debug draw needed
        /// by indexing directly into clusters base on camera position.
        /// </summary>
        /// <param name="showLinks"></param>
        public override void DebugDraw(Boolean showLinks)
        {
            //DebugCheckNodes();

            Color col = Color.Orange;

            // How many pixels wide/high is a single cluster? This will be needed to go from
            // screen size, to cluster index.
            Int32 pixelsPerClusterX = mClusterSize * mGetMapInfoMsg.mInfo_Out.mTileWidth;
            Int32 pixelsPerClusterY = mClusterSize * mGetMapInfoMsg.mInfo_Out.mTileHeight;

            // Based on the current position of the camera, figure out where in the array of clusters they
            // start to become visible on screen. Also figure out where they stop being visible again.
            MBHEngine.Math.Rectangle view = CameraManager.pInstance.pViewRect;
            Int32 startX = (Int32)MathHelper.Max((Int32)view.pLeft / pixelsPerClusterX, 0);
            Int32 endX   = (Int32)MathHelper.Min((Int32)view.pRight / pixelsPerClusterX + 1, mClusters.GetLength(0));
            Int32 startY = (Int32)MathHelper.Max((Int32)view.pTop / pixelsPerClusterY, 0);
            Int32 endY   = (Int32)MathHelper.Min((Int32)view.pBottom / pixelsPerClusterY + 1, mClusters.GetLength(1));

            for (Int32 y = startY; y < endY; y++)
            {
                for (Int32 x = startX; x < endX; x++)
                {
                    Cluster temp = mClusters[x, y];

                    for (Int32 i = 0; i < temp.pNodes.Count; i++)
                    {
                        DrawNode(temp.pNodes[i], showLinks);
                    }

                    // Render the cluster boundaries as well.
                    MBHEngine.Math.Rectangle tempRect = temp.pTopLeft.mCollisionRect;
                    //DebugShapeDisplay.pInstance.AddAABB(tempRect, col);
                    DebugShapeDisplay.pInstance.AddAABB(temp.pBounds, col, false);
                }
            }
        }
        /// <summary>
        /// Call this to initialize an GameObject with data supplied in a file.
        /// </summary>
        /// <param name="fileName">The file to load from.</param>
        public virtual void LoadContent(String fileName)
        {
            // Give this object a unique id and increment the counter so that the next
            // object gets a unique id as well.
            mID = mUniqueIDCounter++;

            mDirection          = new Direction();
            mFactoryInfo        = new GameObjectFactory.FactoryInfo();
            mClassifications    = new List <GameObjectDefinition.Classifications>();
            mCollisionRectangle = new Math.Rectangle();
            mRenderRectangle    = new Math.Rectangle();

            mTemplateFileName = fileName;

            if (null != fileName)
            {
                GameObjectDefinition def = GameObjectManager.pInstance.pContentManager.Load <GameObjectDefinition>(fileName);

                mRenderPriority     = def.mRenderPriority;
                mDoUpdate           = def.mDoUpdate;
                mDoRender           = def.mDoRender;
                mPosition           = def.mPosition;
                mRotation           = def.mRotation;
                mScale              = def.mScale;
                mIsStatic           = def.mIsStatic;
                mCollisionRectangle = new Math.Rectangle(def.mCollisionBoxDimensions);
                mCollisionRectangle.pCenterPoint = mPosition;
                // Being lazy for now. Just assume that a scaler of collision box is big enough to always show character.
                mRenderRectangle = new Math.Rectangle(def.mCollisionBoxDimensions * 4f);
                mRenderRectangle.pCenterPoint = mPosition;
                mMotionRoot = def.mMotionRoot;
                if (def.mCollisionRoot == null)
                {
                    mCollisionRoot = Vector2.Zero;
                }
                else
                {
                    mCollisionRoot = def.mCollisionRoot;
                }

                for (Int32 i = 0; def.mClassifications != null && i < def.mClassifications.Count; i++)
                {
                    mClassifications.Add(def.mClassifications[i]);
                }

                mBlendMode = def.mBlendMode;

                for (Int32 i = 0; i < def.mBehaviourFileNames.Count; i++)
                {
                    String goRootPath        = System.IO.Path.GetDirectoryName(fileName);
                    Behaviour.Behaviour temp = CreateBehaviourByName(def.mBehaviourClassNames[i], goRootPath + "\\Behaviours\\" + def.mBehaviourFileNames[i]);
                    mBehaviours.Add(temp);
                }
            }
            else
            {
                mRenderPriority = 50;
                mDoUpdate       = true;
                mDoRender       = true;
                mBlendMode      = GameObjectDefinition.BlendMode.STANDARD;
            }
        }
Example #6
0
        /// <summary>
        /// Perform the path finding. Call repeatedly to continue to try and find the path over a number
        /// of frames.
        /// </summary>
        /// <param name="restrictedArea">Restrict choosen nodes to this area.</param>
        /// <returns>The result of the path finding for this frame.</returns>
        public Result PlanPath(MBHEngine.Math.Rectangle restrictedArea = null, Boolean drawDebug = true)
        {
            // If there is no tile at the destination then there is no path finding to do.
            if (mEnd == null)
            {
                return(Result.NotStarted);
            }

            if (drawDebug)
            {
                // If we have a destination draw it. Even if there isn't a source yet.
                DebugShapeDisplay.pInstance.AddPoint(mEnd.pPosition, 2.0f, Color.Yellow);
            }

            // If the destination is a solid tile then we will never be able to solve the path.
            if (null != mEnd && !mEnd.IsEmpty())
            {
                // We consider this a failure, similar to if a destination was surrounded by solid.
                return(Result.InvalidLocation);
            }

            // If our source position is not on a tile then there is no path finding to do.
            if (mStart == null)
            {
                return(Result.NotStarted);
            }

            // If our source position is not on a tile, or that tile is solid we cannot ever solve
            // this path, so abort right away.
            if (mStart != null && !mStart.IsEmpty())
            {
                // Trying to path find to a solid tile is considered a failure.
                return(Result.InvalidLocation);
            }

            if (drawDebug)
            {
                // If there is a source, draw it.
                DebugShapeDisplay.pInstance.AddPoint(mStart.pPosition, 2.0f, Color.Orange);
            }

            // If the path hasn't already been invalidated this frame, we need to check that
            // the path didn't get blocked from something like the Player placing blocks.
            // TODO: This could be changed to only do this check when receiving specific events,
            //       such as the ObjectPlacement Behaviour telling it that a new block has been
            //       placed.
            if (!mPathInvalidated)
            {
                // Loop through the current path and check for any tiles that are not
                // empty. If they aren't empty this path is no longer valid as there is
                // something now blocking it.
                //
                PathNode node = mBestPathEnd;

                while (null != node)
                {
                    if (!node.pGraphNode.IsEmpty())
                    {
                        // Setting this flag will force the path finder to start from
                        // the begining.
                        mPathInvalidated = true;

                        // No need to loop any further. One blockade is enough.
                        break;
                    }

                    node = node.pPrevious;
                }
            }

            // If the path has become invalid, we need to restart the pathing algorithm.
            if (mPathInvalidated)
            {
                ClearNodeLists();

                // First thing we need to do is add the first node to the open list.
                PathNode p = mUnusedNodes.Pop();
                p.pGraphNode = mStart;

                // There is no cost because it is the starting node.
                p.pCostFromStart = 0;

                // For H we use the actual distance to the destination.  The Manhattan Heuristic method.

                /*
                 * p.pCostToEnd = System.Math.Max(System.Math.Abs(
                 *      p.pGraphNode.pPosition.X - mEnd.pPosition.X),
                 *      System.Math.Abs(p.pGraphNode.pPosition.Y - mEnd.pPosition.Y));
                 */

                Vector2 source = p.pGraphNode.pPosition;

                Single h_diagonal = System.Math.Min(System.Math.Abs(source.X - mEnd.pPosition.X), System.Math.Abs(source.Y - mEnd.pPosition.Y));
                Single h_straight = System.Math.Abs(source.X - mEnd.pPosition.X) + System.Math.Abs(source.Y - mEnd.pPosition.Y);
                p.pCostToEnd = (11.314f) * h_diagonal + 8.0f * (h_straight - 2 * h_diagonal);

                // Add it to the list, and start the search!
                mOpenNodes.Add(p);

                // If the path was invalidated that assume that it is not longer solved.
                mSolved = false;

                // The path is no longer invalid.  It has begun.
                mPathInvalidated = false;
            }

            // Track how many times this planner has looped this time.
            Int32 count = 0;

            const Int32 maxLoops = 30;

            // Loop until all possibilities have been exhusted, the time slice is expired or the
            // path is solved.
            while (mOpenNodes.Count > 0 && count < maxLoops && !mSolved)// && (!drawDebug || Input.InputManager.pInstance.CheckAction(Input.InputManager.InputActions.B, true)))
            {
                count++;

                mBestPathEnd = mOpenNodes[0];

                //HPAStar.NavMesh.DebugCheckNode(mBestPathEnd.pGraphNode);

                for (Int32 i = 0; i < mOpenNodes.Count; i++)
                {
                    if (mOpenNodes[i].pFinalCost <= mBestPathEnd.pFinalCost)
                    {
                        mBestPathEnd = mOpenNodes[i];
                    }
                }

                mOpenNodes.Remove(mBestPathEnd);
                mClosedNodes.Add(mBestPathEnd);

                // End the search once the destination node is added to the closed list.
                //
                if (mBestPathEnd.pGraphNode == mEnd)
                {
                    OnPathSolved(drawDebug);

                    mSolved = true;

                    break;
                }

                for (Int32 i = 0; i < mBestPathEnd.pGraphNode.pNeighbours.Count; i++)
                {
                    GraphNode.Neighbour nextNode = mBestPathEnd.pGraphNode.pNeighbours[i];

                    if (nextNode.mGraphNode.IsPassable(mBestPathEnd.pGraphNode) && (restrictedArea == null || restrictedArea.Intersects(nextNode.mGraphNode.pPosition)))
                    {
                        Boolean found = false;
                        for (Int32 j = 0; j < mClosedNodes.Count; j++)
                        {
                            if (mClosedNodes[j].pGraphNode == nextNode.mGraphNode)
                            {
                                found = true;
                                break;
                            }
                        }

                        // This node is already in the closed list, so move on to the next node.
                        if (found)
                        {
                            continue;
                        }

                        // 3-b. If it isn’t on the open list, add it to the open list.
                        // Make the current square the parent of this square. Record the F, G, and H costs of the square.

                        // TODO: Get a better way to know if something is in the opened list already.
                        //
                        PathNode foundNode = null;

                        for (Int32 j = 0; j < mOpenNodes.Count; j++)
                        {
                            if (mOpenNodes[j].pGraphNode == nextNode.mGraphNode)
                            {
                                foundNode = mOpenNodes[j];
                                break;
                            }
                        }

                        // Calculate the cost of moving to this node.  This is the distance between the two nodes.
                        // This will be needed in both the case where the node is in the open list already,
                        // and the case where it is not.
                        // The cost is the cost of the previous node plus the distance cost to this node.
                        Single costFromCurrentBest = mBestPathEnd.pCostFromStart + nextNode.mCostToTravel;

                        // If the node was not found it needs to be added to the open list.
                        if (foundNode == null)
                        {
                            // Create a new node and add it to the open list so it can been considered for pathing
                            // in the updates to follow.
                            PathNode p = mUnusedNodes.Pop();
                            p.pGraphNode = nextNode.mGraphNode;

                            // For now it points back to the current node.  This can be overwritten if another node
                            // leads here with a lower cost (see else statement below).
                            p.pPrevious = mBestPathEnd;

                            // The cost to get to this node (G) is calculated above.
                            p.pCostFromStart = costFromCurrentBest;

                            // Combo

                            Vector2 source = p.pGraphNode.pPosition;

                            Single h_diagonal = System.Math.Min(System.Math.Abs(source.X - mEnd.pPosition.X), System.Math.Abs(source.Y - mEnd.pPosition.Y));
                            Single h_straight = System.Math.Abs(source.X - mEnd.pPosition.X) + System.Math.Abs(source.Y - mEnd.pPosition.Y);
                            p.pCostToEnd = (11.314f) * h_diagonal + 8.0f * (h_straight - 2 * h_diagonal);
                            //p.mCostToEnd *= (10.0f + (1.0f/1000.0f));


                            /*
                             * p.pCostToEnd = System.Math.Max(System.Math.Abs(
                             *                      p.pGraphNode.pPosition.X - mEnd.pPosition.X),
                             *                      System.Math.Abs(p.pGraphNode.pPosition.Y - mEnd.pPosition.Y));
                             */
                            mOpenNodes.Add(p);

                            // Ending the search now will alomost always result in the best path
                            // but it is possible for it to fail.
                            if (p.pGraphNode == mEnd)
                            {
                                // Since the path is now solved, update mCurBest so that it is used for
                                // tracing back through the path from now on.
                                mBestPathEnd = p;

                                OnPathSolved(drawDebug);

                                break;
                            }
                        }
                        else
                        {
                            // If it is on the open list already, check to see if this path to that square is better,
                            // using G cost as the measure. A lower G cost means that this is a better path. If so,
                            // change the parent of the square to the current square, and recalculate the G and F
                            // scores of the square. If you are keeping your open list sorted by F score, you may need
                            // to resort the list to account for the change.
                            if (foundNode.pCostFromStart > costFromCurrentBest)
                            {
                                foundNode.pPrevious      = mBestPathEnd;
                                foundNode.pCostFromStart = costFromCurrentBest;
                            }
                        }
                    }
                }
            }

            // Draw the path.
            if (drawDebug && mBestPathEnd != null)
            {
                DebugDraw();
            }

            if (mSolved)
            {
                return(Result.Solved);
            }
            else if (mOpenNodes.Count > 0)
            {
                return(Result.InProgress);
            }
            else
            {
                return(Result.Failed);
            }
        }
 /// <summary>
 /// Checks if a Rectangle is on screen at all.
 /// </summary>
 /// <param name="rect">The rectangle to check.</param>
 /// <returns></returns>
 public Boolean IsOnCamera(MBHEngine.Math.Rectangle rect)
 {
     return(mViewRectangle.Intersects(rect));
 }
        /// <summary>
        /// Initialize the singleton.  Call before first use.
        /// </summary>
        /// <param name="device">The initialized graphics device.  Used to calculate screen position.</param>
        public void Initialize(GraphicsDevice device)
        {
            mTransform = Matrix.Identity;
            mTargetPosition = new Vector2(GameObjectManager.pInstance.pGraphics.PreferredBackBufferWidth * 0.5f, GameObjectManager.pInstance.pGraphics.PreferredBackBufferHeight * 0.5f);
            mLastPosition = new Vector2();
            mCurBlendFrames = 0;
            mCurZoomBlendFrames = 0;

            mBlendFrames = 10;
            mZoomBlendFrames = 0;

            mScreenCenter = Matrix.CreateTranslation(GameObjectManager.pInstance.pGraphics.PreferredBackBufferWidth * 0.5f, GameObjectManager.pInstance.pGraphics.PreferredBackBufferHeight * 0.5f, 0);
#if WINDOWS_PHONE
            mZoomAmount = 4.0f;
#elif __ANDROID__

            float originalHeight = 144.0f; 
            float originalWidth = 204.8f; 
            float originalScale = 1.0f; // at originalHeight/width the scale should be...

            float scaleToOrigialY = GameObjectManager.pInstance.pGraphics.PreferredBackBufferHeight / originalHeight;
            float scaleToOrigialX = GameObjectManager.pInstance.pGraphics.PreferredBackBufferWidth / originalWidth;

            Console.WriteLine(
                "Res: " +
                GameObjectManager.pInstance.pGraphics.PreferredBackBufferWidth.ToString() + 
                "x" + 
                GameObjectManager.pInstance.pGraphics.PreferredBackBufferHeight.ToString());

            mZoomAmount = originalScale * scaleToOrigialY;
#elif SMALL_WINDOW
            mZoomAmount = 3.2f;
#else
            mZoomAmount = 6.4f;
#endif

            mTargetZoomAmount = mDefaultZoomAmount = mZoomAmount;

            mTransform =
                Matrix.CreateTranslation(-new Vector3(0f, 0f, 0.0f)) *
                //Matrix.CreateRotationZ(Rotation) *
                Matrix.CreateScale(new Vector3(mZoomAmount)) *
                mScreenCenter;

            mTransformUI = Matrix.CreateScale(new Vector3(mDefaultZoomAmount));

            mViewRectangle = new Math.Rectangle();

            // Find the center of the screen.
            Single x = ((GameObjectManager.pInstance.pGraphics.PreferredBackBufferWidth * 0.5f) / pZoomScale);
            Single y = ((GameObjectManager.pInstance.pGraphics.PreferredBackBufferHeight * 0.5f) / pZoomScale);

            // Since the screen always has 0,0 at the top left of the screen, we can get the width and height simply
            // by doubling the center point.
            Single width = x * 2;
            Single height = y * 2;

            // This rectangle should never change (unless we change resolutions).
            mScreenRectangle = new Math.Rectangle(new Vector2(width, height), new Vector2(x, y));
        }