]> Dogcows Code - chaz/carfire/blob - CarFire/CarFire/CarFire/SaberMonster2.cs
Merged sabermonster2.
[chaz/carfire] / CarFire / CarFire / CarFire / SaberMonster2.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 /// <summary>
12 /// A type for the states of an artificually intelligent entity.
13 /// </summary>
14 public enum AiState
15 {
16 Standing,
17 Pacing,
18 Chasing,
19 Dazed,
20 Fighting,
21 Retreating
22 }
23
24
25 /// <summary>
26 /// An example monster. This can serve as a starting place for
27 /// creating other monsters. This one just follows a path.
28 /// </summary>
29 public class SaberMonster2 : IMonster
30 {
31 //starting health
32 int health = 100;
33 /// <summary>
34 /// Construct this type of monster. This constructor is called
35 /// by the map when the game requests entities.
36 /// </summary>
37 /// <param name="identifier">The single character ID.</param>
38 /// <param name="position">The initial position on the map.</param>
39 /// <param name="info">More parameters.</param>
40 /// <param name="game">The game object reference.</param>
41 public SaberMonster2(char identifier, Point position, Dictionary<string, string> info, Game game)
42 {
43 mId = identifier;
44 mMotion = new MovementManager(position);
45 mRetryInterval = 2 + (position.X * 25789 + position.Y * 259) % 30;
46
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 // Start doing something...
73 //StartPacing();
74 }
75
76 public void DefaultAction()
77 {
78 mState = AiState.Standing;
79 }
80
81 public void Chasing(Point Chase)
82 {
83 Chasing(Chase.X, Chase.Y);
84 }
85
86 /// <summary>
87 /// Call this to switch the monster AI state to Chasing and set up
88 /// the initial paths. A path to .
89 /// </summary>
90 public void Chasing(int X, int Y)
91 {
92 mState = AiState.Chasing;
93
94 // Determine the best (closest) waypoint to start at.
95 // We may not be on the path, so we have to walk to get on it.
96 /*
97 mIdlePathIndex = 0;
98 int closest = int.MaxValue;
99 for (int i = 0; i < mIdlePath.Count; i++)
100 {
101 int distance = PathFinder.GetManhattanDistance(Coordinates, mIdlePath[i]);
102 if (distance < closest)
103 {
104 mIdlePathIndex = i;
105 closest = distance;
106 }
107 }
108 */
109
110 SetWaypoint(new Point(X, Y));
111 ChartPath();
112 }
113
114 /// <summary>
115 /// Call this to switch the monster AI state to pacing and set up
116 /// the initial paths. The monster will start following the path it
117 /// was defined with in the map file.
118 /// </summary>
119 public void StartPacing()
120 {
121 if (mWaypoints.Count == 0) return;
122
123 mState = AiState.Pacing;
124
125 // Determine the best (closest) waypoint to start at.
126 // We may not be on the path, so we have to walk to get on it.
127 mWaypointIndex = 0;
128 int closest = int.MaxValue;
129 for (int i = 0; i < mWaypoints.Count; i++)
130 {
131 int distance = PathFinder.GetManhattanDistance(Coordinates, mWaypoints[i]);
132 if (distance < closest)
133 {
134 mWaypointIndex = i;
135 closest = distance;
136 }
137 }
138
139 // Find the path to get to the closest waypoint.
140 ChartPath();
141 }
142
143 Direction GetDirectionToNextCell()
144 {
145 if (mPath != null)
146 {
147 if (mPathIndex >= mPath.Count)
148 {
149 // We're done with the current path, so find the path to
150 // the next waypoint... forever.
151 switch (mState)
152 {
153 case AiState.Pacing:
154 SetWaypoint();
155 ChartPath();
156 break;
157
158 default:
159 mPathIndex = 0;
160 mPath = null;
161 mPathDirection = Direction.None;
162 break;
163 }
164 }
165
166 // We need to make sure our direction is set to the next cell
167 // we want to be. If our current coordinates match that, we need
168 // to change our direction to get to the next cell.
169 else if (mPath[mPathIndex] == mMotion.Coordinates)
170 {
171 mPathIndex++;
172 mPathDirection = MovementManager.GetDirection(mMotion.Coordinates, mPath[mPathIndex % mPath.Count]);
173 }
174
175 return mPathDirection;
176 }
177 else return Direction.None;
178 }
179
180 void SetWaypoint()
181 {
182 mWaypointIndex++;
183 mWaypoint = mWaypoints[mWaypointIndex % mWaypoints.Count];
184 }
185
186 void SetWaypoint(Point point)
187 {
188 mWaypoint = point;
189 }
190
191 void ChartPath()
192 {
193 if (mPathSearch == null)
194 {
195 PathFinder pathFinder = new PathFinder(mGame.Grid);
196 Point? nearby = pathFinder.GetNearbyOpenCell(mWaypoint);
197 if (nearby != null) mPathSearch = pathFinder.GetPathAsync(mMotion.Coordinates, nearby.Value);
198
199 mPathIndex = 0;
200 mPath = null;
201 }
202 else if (mPathSearch.IsCompleted)
203 {
204 mPath = (List<Point>)mPathSearch.Path;
205 mPathSearch = null;
206
207 if (mPath != null) mPathDirection = MovementManager.GetDirection(mMotion.Coordinates, mPath[0]);
208 }
209 }
210
211
212 #region IMonster Members
213
214 /// <summary>
215 /// I don't know what this is for.
216 /// </summary>
217 public bool visible
218 {
219 get { throw new NotImplementedException(); }
220 }
221
222 #endregion
223
224
225 #region ICharacter Members
226
227 /// <summary>
228 /// Load the monster's content. This is called by the map when
229 /// the game requests the entities.
230 /// </summary>
231 /// <param name="contentManager">The zaphnod.</param>
232 public void LoadContent(ContentManager contentManager)
233 {
234 mTexture = contentManager.Load<Texture2D>("menuItem");
235 }
236
237 /// <summary>
238 /// Update the monster's state. This should be called by the game
239 /// every "frame" (whenever the game is updating its state). In this
240 /// simple monster, all we need to do is update the motion manager.
241 /// </summary>
242 /// <param name="timeSpan"></param>
243 public void Update(TimeSpan timeSpan)
244 {
245 int closestChar = 0;
246 int closestCharDist = 1000;
247 for (int c = 0; c < mGame.State.mCharacters.Length; c++)
248 {
249 if (mGame.State.mCharacters[c] != null && mGame.AIData.spaceVisible(Coordinates, mGame.State.mCharacters[c].Coordinates))
250 {
251 if (PathFinder.GetManhattanDistance(Coordinates, mGame.State.mCharacters[c].Coordinates) < closestCharDist)
252 {
253 closestCharDist = PathFinder.GetManhattanDistance(Coordinates, mGame.State.mCharacters[c].Coordinates);
254 closestChar = c;
255 }
256 }
257 }
258
259 if (mGame.State.mCharacters[closestChar] != null && mGame.AIData.spaceVisible(Coordinates, mGame.State.mCharacters[closestChar].Coordinates))
260 {
261 Chasing(mGame.State.mCharacters[0].Coordinates);
262 }
263 else
264 {
265 DefaultAction();
266 }
267
268 Direction direction = GetDirectionToNextCell();
269 Point destination = MovementManager.GetNeighbor(Coordinates, direction);
270
271 switch (mState)
272 {
273 case AiState.Pacing:
274
275 if (mGame.IsCellOpen(destination))
276 {
277 mMotion.Update(timeSpan, direction);
278 }
279 else
280 {
281 if (mGame.CurrentFrameNumber % mRetryInterval == 0) ChartPath();
282 mMotion.Update(timeSpan);
283 }
284 break;
285
286 case AiState.Chasing:
287
288 if (mGame.IsCellOpen(destination))
289 {
290 mMotion.Update(timeSpan, direction);
291 }
292 else
293 {
294 if (mGame.CurrentFrameNumber % mRetryInterval == 0) ChartPath();
295 mMotion.Update(timeSpan);
296 }
297 break;
298
299 case AiState.Standing:
300 mMotion.Update(timeSpan);
301 break;
302 case AiState.Dazed:
303 case AiState.Fighting:
304 case AiState.Retreating:
305 break;
306
307 }
308 }
309
310 /// <summary>
311 /// Draw the monster. We just ask the map for our screen position,
312 /// passing it the position which the motion manager keeps track of.
313 /// </summary>
314 /// <param name="spriteBatch">The </param>
315 public void Draw(SpriteBatch spriteBatch)
316 {
317 Rectangle position = mGame.State.Map.GetRectangleFromCoordinates(mMotion.Position);
318 spriteBatch.Draw(mTexture, position, Color.White);
319 }
320
321 /// <summary>
322 /// A monster should keep track of its health. This one doesn't.
323 /// </summary>
324 public int Health
325 {
326 get { return this.health; }
327
328 }
329
330 /// <summary>
331 /// This monster is invincible.
332 /// </summary>
333 /// <param name="amount"></param>
334 public void causeDamageTo(int amount)
335 {
336 this.health -= amount;
337 }
338
339 public bool IsCollidable { get { return true; } }
340
341 /// <summary>
342 /// Get the smoothed position.
343 /// </summary>
344 public Vector2 Position { get { return mMotion.Position; } }
345
346 /// <summary>
347 /// Get the grid coordinates.
348 /// </summary>
349 public Point Coordinates {
350 get { return mMotion.Coordinates; }
351 set { mMotion = new MovementManager(value, mMotion.Speed); }
352 }
353
354 /// <summary>
355 /// Get the entity identifier.
356 /// </summary>
357 public char Identifier { get { return mId; } }
358
359 #endregion
360
361
362 #region Private Variables
363
364 Game mGame;
365
366 char mId;
367 MovementManager mMotion;
368 AI mAI;
369 List<Point> mWaypoints = new List<Point>(); // List of waypoints that we got from the map.
370 int mWaypointIndex; // Index to the waypoint we're heading for.
371 Point mWaypoint;
372
373 List<Point> mPath; // List of cells in the path between the position between where
374 // we started and the waypoint we're heading for.
375 int mPathIndex; // Index to the cell we're heading for.
376 Direction mPathDirection; // The direction between our current position and the place we're going.
377 int mRetryInterval;
378 PathFinder.AsyncTask mPathSearch; // If a path search is in progress, this is the task object.
379
380 AiState mState; // What is the monster doing?
381
382 Texture2D mTexture; // Obvious.
383
384 #endregion
385 }
386 }
This page took 0.052587 seconds and 4 git commands to generate.