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