New property IEntity.IsCollidable so entities can let the collision code know whether...
[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
46 // We need to keep the game reference in order to get the grid when we
47 // need to find paths.
48 mGame = game;
49
50 // Get the speed of the monster. If not set in the map, it defaults to
51 // whatever the default of MovementManager is... 1 I think.
52 string speedString;
53 if (info.TryGetValue("speed", out speedString))
54 {
55 int? speed = Parse.Integer(speedString);
56 if (speed != null) mMotion.Speed = speed.Value;
57 }
58
59 // Get the "idle path" coordinates loaded from the map.
60 string idlePath;
61 if (info.TryGetValue("path", out idlePath))
62 {
63 string[] idlePathPoints = Parse.List(idlePath);
64 foreach (string pathPoint in idlePathPoints)
65 {
66 Point? point = Parse.Coordinates(pathPoint);
67 if (point != null) mIdlePath.Add(point.Value);
68 }
69 }
70
71 // Start doing something...
72 StartPacing();
73 }
74
75
76 /// <summary>
77 /// Call this to switch the monster AI state to pacing and set up
78 /// the initial paths. The monster will start following the path it
79 /// was defined with in the map file.
80 /// </summary>
81 public void StartPacing()
82 {
83 mState = AiState.Pacing;
84
85 if (mIdlePath.Count == 0) return;
86
87 // Determine the best (closest) waypoint to start at.
88 // We may not be on the path, so we have to walk to get on it.
89 mIdlePathIndex = 0;
90 int closest = int.MaxValue;
91 for (int i = 0; i < mIdlePath.Count; i++)
92 {
93 int distance = PathFinder.GetManhattanDistance(Coordinates, mIdlePath[i]);
94 if (distance < closest)
95 {
96 mIdlePathIndex = i;
97 closest = distance;
98 }
99 }
100
101 // Find the path to get to the closest waypoint.
102 PathFinder pathFinder = new PathFinder(mGame.Grid);
103 mPath = new List<Point>(32);
104 mPath.Add(Coordinates);
105 List<Point> path = pathFinder.GetPath(mMotion.Coordinates, mIdlePath[mIdlePathIndex]);
106 if (path != null)
107 {
108 mPath.AddRange(path);
109 mPath.Add(mIdlePath[mIdlePathIndex]);
110 }
111 mPathIndex = 0;
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 mIdlePathIndex++;
121 PathFinder pathFinder = new PathFinder(mGame.Grid);
122 mPath = new List<Point>(32);
123 mPath.Add(Coordinates);
124 List<Point> path = pathFinder.GetPath(mMotion.Coordinates, mIdlePath[mIdlePathIndex % mIdlePath.Count]);
125 if (path != null)
126 {
127 mPath.AddRange(path);
128 mPath.Add(mIdlePath[mIdlePathIndex % mIdlePath.Count]);
129 }
130 mPathIndex = 0;
131 }
132
133 // We need to make sure out direction is set to the next cell
134 // we want to be. If our current coordinates match that, we need
135 // to change our direction to get to the next cell.
136 if (mPath[mPathIndex % mPath.Count] == mMotion.Coordinates)
137 {
138 mPathIndex++;
139 mPathDirection = MovementManager.GetDirection(mMotion.Coordinates, mPath[mPathIndex % mPath.Count]);
140 }
141
142 return mPathDirection;
143 }
144
145
146 #region IMonster Members
147
148 /// <summary>
149 /// I don't know what this is for.
150 /// </summary>
151 public bool visible
152 {
153 get { throw new NotImplementedException(); }
154 }
155
156 #endregion
157
158
159 #region ICharacter Members
160
161 /// <summary>
162 /// Load the monster's content. This is called by the map when
163 /// the game requests the entities.
164 /// </summary>
165 /// <param name="contentManager">The zaphnod.</param>
166 public void LoadContent(ContentManager contentManager)
167 {
168 mTexture = contentManager.Load<Texture2D>("menuItem");
169 }
170
171 /// <summary>
172 /// Update the monster's state. This should be called by the game
173 /// every "frame" (whenever the game is updating its state). In this
174 /// simple monster, all we need to do is update the motion manager.
175 /// </summary>
176 /// <param name="timeSpan"></param>
177 public void Update(TimeSpan timeSpan)
178 {
179 if (mState == AiState.Pacing)
180 {
181 mMotion.Update(timeSpan, GetDirectionToNextCell());
182 }
183 }
184
185 /// <summary>
186 /// Draw the monster. We just ask the map for our screen position,
187 /// passing it the position which the motion manager keeps track of.
188 /// </summary>
189 /// <param name="spriteBatch">The </param>
190 public void Draw(SpriteBatch spriteBatch)
191 {
192 Rectangle position = mGame.State.Map.GetRectangleFromCoordinates(mMotion.Position);
193 spriteBatch.Draw(mTexture, position, Color.White);
194 }
195
196 /// <summary>
197 /// A monster should keep track of its health. This one doesn't.
198 /// </summary>
199 public int Health
200 {
201 get { return this.health; }
202
203 }
204
205 /// <summary>
206 /// This monster is invincible.
207 /// </summary>
208 /// <param name="amount"></param>
209 public void causeDamageTo(int amount)
210 {
211 this.health -= amount;
212 }
213
214 public bool IsCollidable { get { return true; } }
215
216 /// <summary>
217 /// Get the smoothed position.
218 /// </summary>
219 public Vector2 Position { get { return mMotion.Position; } }
220
221 /// <summary>
222 /// Get the grid coordinates.
223 /// </summary>
224 public Point Coordinates { get { return mMotion.Coordinates; } }
225
226 #endregion
227
228
229 #region Private Variables
230
231 Game mGame;
232
233 char mId;
234 MovementManager mMotion;
235
236 List<Point> mIdlePath = new List<Point>(); // List of waypoints that we got from the map.
237 int mIdlePathIndex; // Index to the waypoint we're heading for.
238
239 List<Point> mPath; // List of cells in the path between the position between where
240 // we started and the waypoint we're heading for.
241 int mPathIndex; // Index to the cell we're heading for.
242 Direction mPathDirection; // The direction between our current position and the place we're going.
243
244 AiState mState; // What is the monster doing?
245
246 Texture2D mTexture; // Obvious.
247
248 #endregion
249 }
250 }
This page took 0.053966 seconds and 4 git commands to generate.