Adding AI to monsters. AI still has some bugs to be worked out. Put it should compile...
[chaz/carfire] / CarFire / CarFire / CarFire / SaberMonster.cs
1 ´╗┐using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using Microsoft.Xna.Framework;
6 using Microsoft.Xna.Framework.Content;
7 using Microsoft.Xna.Framework.Graphics;
8
9 namespace CarFire
10 {
11 /*
12 /// <summary>
13 /// A type for the states of an artificually intelligent entity.
14 /// </summary>
15 public enum AiState
16 {
17 Standing,
18 Pacing,
19 Chasing,
20 Dazed,
21 Fighting,
22 Retreating
23 }
24 */
25
26 /// <summary>
27 /// An example monster. This can serve as a starting place for
28 /// creating other monsters. This one just follows a path.
29 /// </summary>
30 public class SaberMonster : IMonster
31 {
32 //starting health
33 int health = 100;
34 /// <summary>
35 /// Construct this type of monster. This constructor is called
36 /// by the map when the game requests entities.
37 /// </summary>
38 /// <param name="identifier">The single character ID.</param>
39 /// <param name="position">The initial position on the map.</param>
40 /// <param name="info">More parameters.</param>
41 /// <param name="game">The game object reference.</param>
42 public SaberMonster(char identifier, Point position, Dictionary<string, string> info, Game game)
43 {
44 mId = identifier;
45 mMotion = new MovementManager(position);
46 mRetryInterval = 20 + (position.X * 25789 + position.Y * 259) % 30;
47
48 // We need to keep the game reference in order to get the grid when we
49 // need to find paths.
50 mGame = game;
51
52 // Get the speed of the monster. If not set in the map, it defaults to
53 // whatever the default of MovementManager is... 1 I think.
54 string speedString;
55 if (info.TryGetValue("speed", out speedString))
56 {
57 int? speed = Parse.Integer(speedString);
58 if (speed != null) mMotion.Speed = speed.Value;
59 }
60
61 // Get the "idle path" coordinates loaded from the map.
62 string idlePath;
63 if (info.TryGetValue("path", out idlePath))
64 {
65 string[] idlePathPoints = Parse.List(idlePath);
66 foreach (string pathPoint in idlePathPoints)
67 {
68 Point? point = Parse.Coordinates(pathPoint);
69 if (point != null) mWaypoints.Add(point.Value);
70 }
71 }
72
73 // Start doing something...
74 StartPacing();
75 }
76 public void DefaultAction()
77 {
78
79 }
80 public void Chasing(Point Chase)
81 {
82
83 }
84
85 /// <summary>
86 /// Call this to switch the monster AI state to pacing and set up
87 /// the initial paths. The monster will start following the path it
88 /// was defined with in the map file.
89 /// </summary>
90 public void StartPacing()
91 {
92 if (mWaypoints.Count == 0) return;
93
94 mState = AiState.Pacing;
95
96 // Determine the best (closest) waypoint to start at.
97 // We may not be on the path, so we have to walk to get on it.
98 mWaypointIndex = 0;
99 int closest = int.MaxValue;
100 for (int i = 0; i < mWaypoints.Count; i++)
101 {
102 int distance = PathFinder.GetManhattanDistance(Coordinates, mWaypoints[i]);
103 if (distance < closest)
104 {
105 mWaypointIndex = i;
106 closest = distance;
107 }
108 }
109
110 // Find the path to get to the closest waypoint.
111 ChartPath();
112 }
113
114 Direction GetDirectionToNextCell()
115 {
116 if (mPathIndex >= mPath.Count)
117 {
118 // We're done with the current path, so find the path to
119 // the next waypoint... forever.
120 mWaypointIndex++;
121 ChartPath();
122 }
123
124 // We need to make sure our direction is set to the next cell
125 // we want to be. If our current coordinates match that, we need
126 // to change our direction to get to the next cell.
127 if (mPathIndex < mPath.Count && mPath[mPathIndex] == mMotion.Coordinates)
128 {
129 mPathIndex++;
130 mPathDirection = MovementManager.GetDirection(mMotion.Coordinates, mPath[mPathIndex % mPath.Count]);
131 }
132
133 return mPathDirection;
134 }
135
136 void ChartPath()
137 {
138 mPath = new List<Point>(32);
139
140 Point waypoint = mWaypoints[mWaypointIndex % mWaypoints.Count];
141 PathFinder pathFinder = new PathFinder(mGame.Grid);
142 List<Point> path = pathFinder.GetPath(mMotion.Coordinates, waypoint);
143 if (path != null) mPath.AddRange(path);
144
145 mPathIndex = 0;
146 if (mPathIndex < mPath.Count) mPathDirection = MovementManager.GetDirection(mMotion.Coordinates, mPath[mPathIndex]);
147 else mPathDirection = Direction.None;
148 }
149
150
151 #region IMonster Members
152
153 /// <summary>
154 /// I don't know what this is for.
155 /// </summary>
156 public bool visible
157 {
158 get { throw new NotImplementedException(); }
159 }
160
161 #endregion
162
163
164 #region ICharacter Members
165
166 /// <summary>
167 /// Load the monster's content. This is called by the map when
168 /// the game requests the entities.
169 /// </summary>
170 /// <param name="contentManager">The zaphnod.</param>
171 public void LoadContent(ContentManager contentManager)
172 {
173 mTexture = contentManager.Load<Texture2D>("default");
174 }
175
176 /// <summary>
177 /// Update the monster's state. This should be called by the game
178 /// every "frame" (whenever the game is updating its state). In this
179 /// simple monster, all we need to do is update the motion manager.
180 /// </summary>
181 /// <param name="timeSpan"></param>
182 public void Update(TimeSpan timeSpan)
183 {
184 switch (mState)
185 {
186 case AiState.Pacing:
187
188 Direction direction = GetDirectionToNextCell();
189 Point destination = MovementManager.GetNeighbor(Coordinates, direction);
190
191 if (mGame.IsCellOpen(destination))
192 {
193 mMotion.Update(timeSpan, direction);
194 }
195 else
196 {
197 if (mGame.CurrentFrameNumber % mRetryInterval == 0)
198 {
199 // Something is in our way, so let's chart a new course.
200 ChartPath();
201
202 direction = GetDirectionToNextCell();
203 /*if (direction == Direction.None)
204 {
205 // If we still can't chart a course, just stand there
206 // and try to chart again later.
207 mState = AiState.Standing;
208 }*/
209
210 mMotion.Update(timeSpan, direction);
211 }
212 else mMotion.Update(timeSpan);
213 }
214
215 break;
216
217 case AiState.Standing:
218
219 mMotion.Update(timeSpan);
220 break;
221 }
222 }
223
224 /// <summary>
225 /// Draw the monster. We just ask the map for our screen position,
226 /// passing it the position which the motion manager keeps track of.
227 /// </summary>
228 /// <param name="spriteBatch">The </param>
229 public void Draw(SpriteBatch spriteBatch)
230 {
231 Rectangle position = mGame.State.Map.GetRectangleFromCoordinates(mMotion.Position);
232 spriteBatch.Draw(mTexture, position, Color.White);
233 }
234
235 /// <summary>
236 /// A monster should keep track of its health. This one doesn't.
237 /// </summary>
238 public int Health
239 {
240 get { return this.health; }
241
242 }
243
244 /// <summary>
245 /// This monster is invincible.
246 /// </summary>
247 /// <param name="amount"></param>
248 public void causeDamageTo(int amount)
249 {
250 this.health -= amount;
251 }
252
253 public bool IsCollidable { get { return true; } }
254
255 /// <summary>
256 /// Get the smoothed position.
257 /// </summary>
258 public Vector2 Position { get { return mMotion.Position; } }
259
260 /// <summary>
261 /// Get the grid coordinates.
262 /// </summary>
263 public Point Coordinates {
264 get { return mMotion.Coordinates; }
265 set { mMotion = new MovementManager(value, mMotion.Speed); }
266 }
267
268 /// <summary>
269 /// Get the entity identifier.
270 /// </summary>
271 public char Identifier { get { return mId; } }
272
273 #endregion
274
275
276 #region Private Variables
277
278 Game mGame;
279
280 char mId;
281 MovementManager mMotion;
282
283 List<Point> mWaypoints = new List<Point>(); // List of waypoints that we got from the map.
284 int mWaypointIndex; // Index to the waypoint we're heading for.
285
286 List<Point> mPath; // List of cells in the path between the position between where
287 // we started and the waypoint we're heading for.
288 int mPathIndex; // Index to the cell we're heading for.
289 Direction mPathDirection; // The direction between our current position and the place we're going.
290 int mRetryInterval;
291
292 AiState mState; // What is the monster doing?
293
294 Texture2D mTexture; // Obvious.
295
296 #endregion
297 }
298 }
This page took 0.057584 seconds and 4 git commands to generate.