]> Dogcows Code - chaz/carfire/commitdiff
Adding AI to monsters. AI still has some bugs to be worked out. Put it should compile...
authorbrady <brady@92bb83a3-7c8f-8a45-bc97-515c4e399668>
Tue, 27 Apr 2010 06:32:44 +0000 (06:32 +0000)
committerbrady <brady@92bb83a3-7c8f-8a45-bc97-515c4e399668>
Tue, 27 Apr 2010 06:32:44 +0000 (06:32 +0000)
git-svn-id: https://bd85.net/svn/cs3505_group@159 92bb83a3-7c8f-8a45-bc97-515c4e399668

CarFire/CarFire/CarFire/AI.cs
CarFire/CarFire/CarFire/Content/Content.contentproj
CarFire/CarFire/CarFire/Content/Maps/colosseumClosed.cfmap [new file with mode: 0644]
CarFire/CarFire/CarFire/Game.cs
CarFire/CarFire/CarFire/IPlayer.cs
CarFire/CarFire/CarFire/SaberMonster.cs
CarFire/CarFire/CarFire/SaberMonster2.cs [new file with mode: 0644]

index 8b8a25fd509b91391b7d9451c4758af2d29441f9..716b9787f4a7dea2c1930df4d038ec6086f2dde3 100644 (file)
@@ -63,7 +63,10 @@ namespace CarFire
         {\r
             return regionList[regions[curX, curY]].VisibleRegions.Contains(regions[testX, testY]);\r
         }\r
-\r
+        public bool spaceVisible(Point Monster, Point Player )\r
+        {\r
+            return regionList[regions[Monster.X, Monster.Y]].VisibleRegions.Contains(regions[Player.X, Player.Y]);\r
+        }\r
         //find regions in map. these regions will be large groups of connected grid squares.\r
         public int setUpRegions()\r
         {\r
index 971b51653e262f671361b7f1bee567b4274523de..ef3c88efe64800f5899462b6d71a6f15ce093d1c 100644 (file)
       <Processor>PassThroughProcessor</Processor>\r
     </Compile>\r
   </ItemGroup>\r
-  <ItemGroup>\r
-    <Compile Include="Maps\colosseum.cfmap">\r
-      <Name>colosseum</Name>\r
-      <Importer>MapImporter</Importer>\r
-      <Processor>PassThroughProcessor</Processor>\r
-    </Compile>\r
-  </ItemGroup>\r
   <ItemGroup>\r
     <Compile Include="graphics\blueDemonAttackDieStand.png">\r
       <Name>blueDemonAttackDieStand</Name>\r
       <Processor>TextureProcessor</Processor>\r
     </Compile>\r
   </ItemGroup>\r
+  <ItemGroup>\r
+    <Compile Include="Maps\colosseum.cfmap">\r
+      <Name>colosseum</Name>\r
+      <Importer>MapImporter</Importer>\r
+      <Processor>PassThroughProcessor</Processor>\r
+    </Compile>\r
+    <Compile Include="Maps\colosseumClosed.cfmap">\r
+      <Name>colosseumClosed</Name>\r
+      <Importer>MapImporter</Importer>\r
+      <Processor>PassThroughProcessor</Processor>\r
+    </Compile>\r
+  </ItemGroup>\r
   <Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\v3.0\Microsoft.Xna.GameStudio.ContentPipeline.targets" />\r
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r
        Other similar extension points exist, see Microsoft.Common.targets.\r
diff --git a/CarFire/CarFire/CarFire/Content/Maps/colosseumClosed.cfmap b/CarFire/CarFire/CarFire/Content/Maps/colosseumClosed.cfmap
new file mode 100644 (file)
index 0000000..306e2ab
--- /dev/null
@@ -0,0 +1,76 @@
+; This map should load and function just fine.\r
+\r
+[metadata]\r
+       author = Chaz McGarvey\r
+       levelname = Colosseum\r
+       type = Battle\r
+       dimensions = [41,41]\r
+       tileset = FuturisticBuilding\r
+       numplayers = <1,4>\r
+\r
+[a]\r
+       type = SaberMonster2\r
+       speed = 7\r
+       create = [20,20] [31,31] [2,34] [22,4] [5,7] [18,18] [34,34] [4,20] [37,4] [6,37] [21,21] [21,30] [35,20]\r
+\r
+[b]\r
+       type = SaberMonster2\r
+       speed = 23\r
+       create = [0,4] [4,0]\r
+\r
+[e]\r
+       type = SaberMonster2\r
+       speed = 16\r
+       create = [40,4]\r
+\r
+[c]\r
+       type = SaberMonster2\r
+       speed = 5\r
+       create = [2,2] [20,20] [5,35] [21,34] [34,37] [37,15] [31,31] [2,34] [22,4]\r
+\r
+[d]\r
+       type = SaberMonster2\r
+\r
+[maptable]\r
++---------------------------------------+\r
+|"""               __              """  |\r
+|"1"              _  _             "2"  |\r
+|"""             _    _            """  |\r
+|   """""""""   _      _          "     |\r
+|d           "          _        "      |\r
+|             "          _      "       |\r
+|              "          _     "       |\r
+|           _   "          _    "       |\r
+|          _     "          _   "       |\r
+|         _       "          _  "       |\r
+|        _         "            "       |\r
+|       _           "          "        |\r
+|      _             "        "         |\r
+|     _               "      "   _      |\r
+|    _                 "    "     _     |\r
+|   _                   "  "       _    |\r
+|  _                     ""         _   |\r
+| _                      "           _  |\r
+|_                      "            _  |\r
+|_                     "            _   |\r
+| _                   ""           _    |\r
+|  _                 "  "         _     |\r
+|     """""""""""""""    "       _      |\r
+|    "                    "     _       |\r
+|   "                      "   _        |\r
+|   "  _                    "           |\r
+|   "   _                    "          |\r
+|   "    _                    "         |\r
+|   "     _                _   "        |\r
+|   "      _              _     "       |\r
+|   "       _            _       "      |\r
+|   "        _          _         "     |\r
+|   "         _        _          "     |\r
+|   "          _      _           "     |\r
+|"""            _    _             """  |\r
+|"4"             _  _              "3"  |\r
+|"""              __               """  |\r
+|                                       |\r
+|                                       |\r
++---------------------------------------+\r
+; vi:ft=dosini\r
index 63ed26deed977cd5993c8844496f1f26dfac6852..06aa494320b66fb2f85d046ee823553c6a036c5e 100644 (file)
@@ -31,7 +31,6 @@ namespace CarFire
         public List<Projectile> mProjectiles = new List<Projectile>();\r
         public Player[] mCharacters;\r
         public Display mDisplay;\r
-        public AI AIData;\r
         #endregion\r
 \r
 \r
@@ -422,10 +421,10 @@ namespace CarFire
             Map.Tilemap = tilemap;\r
 \r
             // Load the first map.\r
-            State.Map = mContentManager.Load<Map>("Maps/colosseum");\r
+            State.Map = mContentManager.Load<Map>("Maps/colosseumClosed");\r
             State.Entities = State.Map.GetAllEntities(this);\r
 \r
-            //State.AIData = new AI(this);\r
+            mAIData = new AI(this);\r
 \r
             /*\r
             mPlayers.Clear();\r
@@ -493,7 +492,23 @@ namespace CarFire
         {\r
             State.AdvanceFrame(mInputs, elapsedTime.Milliseconds);  // Apply the inputs, advance game state.\r
             State.mDisplay.Update(elapsedTime, mThisPlayerID);\r
-            State.Entities.ForEach(delegate(IEntity e) { e.Update(elapsedTime); });\r
+            State.Entities.ForEach(delegate(IEntity e) \r
+            {\r
+                IMonster m = e as IMonster;\r
+                if (m != null)\r
+                {\r
+                    if (State.mCharacters[0] != null && mAIData.spaceVisible(e.Coordinates, State.mCharacters[0].Coordinates))\r
+                    {\r
+                        m.Chasing(State.mCharacters[0].Coordinates);\r
+                    }\r
+                    else\r
+                    {\r
+                        m.DefaultAction();\r
+                    }\r
+                }\r
+                e.Update(elapsedTime); \r
+            });\r
+            //State.Entities.ForEach(delegate(IEntity e) { e.Update(elapsedTime); });\r
             mInputs = new NextInputs(State.NumberOfPlayers);  // Start with inputs cleared on the next frame.\r
             //mDisplay.Update(elapsedTime);\r
             return State.FrameNumber;\r
@@ -540,7 +555,7 @@ namespace CarFire
         #region Private Variables\r
 \r
         SpriteFont menu;\r
-\r
+        AI mAIData;\r
         ContentManager mContentManager;\r
         NextInputs mInputs;\r
 \r
index 6f56cef8863132fa8394a61e31e08303a084c77c..f858d1afd2decef1a0ec7d7917dab41c6027ad9a 100644 (file)
@@ -29,6 +29,9 @@ namespace CarFire
 \r
     public interface IMonster : ICharacter\r
     {\r
+        void DefaultAction();\r
+        void Chasing(Point Chase);\r
+        void StartPacing();\r
         bool visible { get; }\r
     }\r
 }\r
index 69b42ca1a44f11d578af78fb4a92fcb5b52b5a9d..a2b5aae9f327ee0f6762e544ebb582d882b673c1 100644 (file)
@@ -8,6 +8,7 @@ using Microsoft.Xna.Framework.Graphics;
 \r
 namespace CarFire\r
 {\r
+    /*\r
     /// <summary>\r
     /// A type for the states of an artificually intelligent entity.\r
     /// </summary>\r
@@ -20,7 +21,7 @@ namespace CarFire
         Fighting,\r
         Retreating\r
     }\r
-\r
+    */\r
 \r
     /// <summary>\r
     /// An example monster.  This can serve as a starting place for\r
@@ -72,7 +73,14 @@ namespace CarFire
             // Start doing something...\r
             StartPacing();\r
         }\r
+        public void DefaultAction()\r
+        {\r
+\r
+        }\r
+        public void Chasing(Point Chase)\r
+        {\r
 \r
+        }\r
 \r
         /// <summary>\r
         /// Call this to switch the monster AI state to pacing and set up\r
diff --git a/CarFire/CarFire/CarFire/SaberMonster2.cs b/CarFire/CarFire/CarFire/SaberMonster2.cs
new file mode 100644 (file)
index 0000000..f522ab4
--- /dev/null
@@ -0,0 +1,305 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using Microsoft.Xna.Framework;\r
+using Microsoft.Xna.Framework.Content;\r
+using Microsoft.Xna.Framework.Graphics;\r
+\r
+namespace CarFire\r
+{\r
+    /// <summary>\r
+    /// A type for the states of an artificually intelligent entity.\r
+    /// </summary>\r
+    public enum AiState\r
+    {\r
+        Standing,\r
+        Pacing,\r
+        Chasing,\r
+        Dazed,\r
+        Fighting,\r
+        Retreating\r
+    }\r
+\r
+\r
+    /// <summary>\r
+    /// An example monster.  This can serve as a starting place for\r
+    /// creating other monsters.  This one just follows a path.\r
+    /// </summary>\r
+    public class SaberMonster2 : IMonster\r
+    {\r
+        //starting health\r
+        int health = 100;\r
+        /// <summary>\r
+        /// Construct this type of monster.  This constructor is called\r
+        /// by the map when the game requests entities.\r
+        /// </summary>\r
+        /// <param name="identifier">The single character ID.</param>\r
+        /// <param name="position">The initial position on the map.</param>\r
+        /// <param name="info">More parameters.</param>\r
+        /// <param name="game">The game object reference.</param>\r
+        public SaberMonster2(char identifier, Point position, Dictionary<string, string> info, Game game)\r
+        {\r
+            mId = identifier;\r
+            mMotion = new MovementManager(position);\r
+\r
+            // We need to keep the game reference in order to get the grid when we\r
+            // need to find paths.\r
+            mGame = game;\r
+\r
+            pathFinder = null;\r
+\r
+            // Get the speed of the monster.  If not set in the map, it defaults to\r
+            // whatever the default of MovementManager is... 1 I think.\r
+            string speedString;\r
+            if (info.TryGetValue("speed", out speedString))\r
+            {\r
+                int? speed = Parse.Integer(speedString);\r
+                if (speed != null) mMotion.Speed = speed.Value;\r
+            }\r
+\r
+            // Get the "idle path" coordinates loaded from the map.\r
+            string idlePath;\r
+            if (info.TryGetValue("path", out idlePath))\r
+            {\r
+                string[] idlePathPoints = Parse.List(idlePath);\r
+                foreach (string pathPoint in idlePathPoints)\r
+                {\r
+                    Point? point = Parse.Coordinates(pathPoint);\r
+                    if (point != null) mIdlePath.Add(point.Value);\r
+                }\r
+            }\r
+            // Start doing something...\r
+            //StartPacing();\r
+        }\r
+\r
+        public void DefaultAction()\r
+        {\r
+            mState = AiState.Standing;\r
+        }\r
+\r
+        public void Chasing(Point Chase)\r
+        {\r
+            Chasing(Chase.X, Chase.Y);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Call this to switch the monster AI state to Chasing and set up\r
+        /// the initial paths.  A path to .\r
+        /// </summary>\r
+        public void Chasing(int X, int Y)\r
+        {\r
+            mState = AiState.Chasing;\r
+\r
+            // Determine the best (closest) waypoint to start at.\r
+            // We may not be on the path, so we have to walk to get on it.\r
+            /*\r
+            mIdlePathIndex = 0;\r
+            int closest = int.MaxValue;\r
+            for (int i = 0; i < mIdlePath.Count; i++)\r
+            {\r
+                int distance = PathFinder.GetManhattanDistance(Coordinates, mIdlePath[i]);\r
+                if (distance < closest)\r
+                {\r
+                    mIdlePathIndex = i;\r
+                    closest = distance;\r
+                }\r
+            }\r
+             */\r
+\r
+            // Find the path to get to the closest waypoint.\r
+            if (pathFinder == null)\r
+                pathFinder = new PathFinder(mGame.Grid);\r
+\r
+            mPath = new List<Point>(32);\r
+            mPath.Add(Coordinates);\r
+            List<Point> path = pathFinder.GetPath(mMotion.Coordinates, new Point(X,Y));\r
+            if (path != null)\r
+            {\r
+                mPath.AddRange(path);\r
+                //mPath.Add(mIdlePath[mIdlePathIndex]);\r
+            }\r
+            mPathIndex = 0;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Call this to switch the monster AI state to pacing and set up\r
+        /// the initial paths.  The monster will start following the path it\r
+        /// was defined with in the map file.\r
+        /// </summary>\r
+        public void StartPacing()\r
+        {\r
+            mState = AiState.Pacing;\r
+\r
+            if (mIdlePath.Count == 0) return;\r
+\r
+            // Determine the best (closest) waypoint to start at.\r
+            // We may not be on the path, so we have to walk to get on it.\r
+            mIdlePathIndex = 0;\r
+            int closest = int.MaxValue;\r
+            for (int i = 0; i < mIdlePath.Count; i++)\r
+            {\r
+                int distance = PathFinder.GetManhattanDistance(Coordinates, mIdlePath[i]);\r
+                if (distance < closest)\r
+                {\r
+                    mIdlePathIndex = i;\r
+                    closest = distance;\r
+                }\r
+            }\r
+\r
+            // Find the path to get to the closest waypoint.\r
+            PathFinder pathFinder = new PathFinder(mGame.Grid);\r
+            mPath = new List<Point>(32);\r
+            mPath.Add(Coordinates);\r
+            List<Point> path = pathFinder.GetPath(mMotion.Coordinates, mIdlePath[mIdlePathIndex]);\r
+            if (path != null)\r
+            {\r
+                mPath.AddRange(path);\r
+                mPath.Add(mIdlePath[mIdlePathIndex]);\r
+            }\r
+            mPathIndex = 0;\r
+        }\r
+\r
+        Direction GetDirectionToNextCell()\r
+        {\r
+            if (mPathIndex >= mPath.Count)\r
+            {\r
+                mState = AiState.Standing;\r
+            }\r
+\r
+            // We need to make sure out direction is set to the next cell\r
+            // we want to be.  If our current coordinates match that, we need\r
+            // to change our direction to get to the next cell.\r
+            if (mPath[mPathIndex % mPath.Count] == mMotion.Coordinates)\r
+            {\r
+                mPathIndex++;\r
+                mPathDirection = MovementManager.GetDirection(mMotion.Coordinates, mPath[mPathIndex % mPath.Count]);\r
+            }\r
+\r
+            return mPathDirection;\r
+        }\r
+\r
+\r
+        #region IMonster Members\r
+\r
+        /// <summary>\r
+        /// I don't know what this is for.\r
+        /// </summary>\r
+        public bool visible\r
+        {\r
+            get { throw new NotImplementedException(); }\r
+        }\r
+\r
+        #endregion\r
+\r
+\r
+        #region ICharacter Members\r
+\r
+        /// <summary>\r
+        /// Load the monster's content.  This is called by the map when\r
+        /// the game requests the entities.\r
+        /// </summary>\r
+        /// <param name="contentManager">The zaphnod.</param>\r
+        public void LoadContent(ContentManager contentManager)\r
+        {\r
+            mTexture = contentManager.Load<Texture2D>("menuItem");\r
+        }\r
+\r
+        /// <summary>\r
+        /// Update the monster's state.  This should be called by the game\r
+        /// every "frame" (whenever the game is updating its state).  In this\r
+        /// simple monster, all we need to do is update the motion manager.\r
+        /// </summary>\r
+        /// <param name="timeSpan"></param>\r
+        public void Update(TimeSpan timeSpan)\r
+        {\r
+            switch (mState)\r
+            {\r
+                case AiState.Pacing:\r
+                case AiState.Chasing:\r
+                    mMotion.Update(timeSpan, GetDirectionToNextCell());\r
+                    break;\r
+                case AiState.Standing:\r
+                case AiState.Dazed:\r
+                case AiState.Fighting:\r
+                case AiState.Retreating:\r
+                    break;\r
+                    \r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Draw the monster.  We just ask the map for our screen position,\r
+        /// passing it the position which the motion manager keeps track of.\r
+        /// </summary>\r
+        /// <param name="spriteBatch">The </param>\r
+        public void Draw(SpriteBatch spriteBatch)\r
+        {\r
+            Rectangle position = mGame.State.Map.GetRectangleFromCoordinates(mMotion.Position);\r
+            spriteBatch.Draw(mTexture, position, Color.White);\r
+        }\r
+\r
+        /// <summary>\r
+        /// A monster should keep track of its health.  This one doesn't.\r
+        /// </summary>\r
+        public int Health\r
+        {\r
+            get { return this.health; }\r
+            \r
+        }\r
+\r
+        /// <summary>\r
+        /// This monster is invincible.\r
+        /// </summary>\r
+        /// <param name="amount"></param>\r
+        public void causeDamageTo(int amount)\r
+        {\r
+            this.health -= amount;\r
+        }\r
+\r
+        public bool IsCollidable { get { return true; } }\r
+\r
+        /// <summary>\r
+        /// Get the smoothed position.\r
+        /// </summary>\r
+        public Vector2 Position { get { return mMotion.Position; } }\r
+\r
+        /// <summary>\r
+        /// Get the grid coordinates.\r
+        /// </summary>\r
+        public Point Coordinates {\r
+            get { return mMotion.Coordinates; }\r
+            set { mMotion = new MovementManager(value, mMotion.Speed); }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Get the entity identifier.\r
+        /// </summary>\r
+        public char Identifier { get { return mId; } }\r
+\r
+        #endregion\r
+\r
+\r
+        #region Private Variables\r
+\r
+        Game mGame;\r
+\r
+        char mId;\r
+        MovementManager mMotion;\r
+\r
+        PathFinder pathFinder;\r
+        List<Point> mIdlePath = new List<Point>();      // List of waypoints that we got from the map.\r
+        int mIdlePathIndex;                             // Index to the waypoint we're heading for.\r
+\r
+        List<Point> mPath;              // List of cells in the path between the position between where\r
+                                        // we started and the waypoint we're heading for.\r
+        int mPathIndex;                 // Index to the cell we're heading for.\r
+        Direction mPathDirection;       // The direction between our current position and the place we're going.\r
+\r
+        AiState mState;                 // What is the monster doing?\r
+\r
+        Texture2D mTexture;             // Obvious.\r
+\r
+        #endregion\r
+    }\r
+}\r
This page took 0.032831 seconds and 4 git commands to generate.