using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace CarFire
{
///
/// A type for the states of an artificually intelligent entity.
///
public enum AiState
{
Standing,
Pacing,
Chasing,
Dazed,
Fighting,
Retreating
}
///
/// An example monster. This can serve as a starting place for
/// creating other monsters. This one just follows a path.
///
public class SaberMonster2 : IMonster
{
//starting health
int health = 100;
///
/// Construct this type of monster. This constructor is called
/// by the map when the game requests entities.
///
/// The single character ID.
/// The initial position on the map.
/// More parameters.
/// The game object reference.
public SaberMonster2(char identifier, Point position, Dictionary info, Game game)
{
mId = identifier;
mMotion = new MovementManager(position);
// We need to keep the game reference in order to get the grid when we
// need to find paths.
mGame = game;
pathFinder = null;
// Get the speed of the monster. If not set in the map, it defaults to
// whatever the default of MovementManager is... 1 I think.
string speedString;
if (info.TryGetValue("speed", out speedString))
{
int? speed = Parse.Integer(speedString);
if (speed != null) mMotion.Speed = speed.Value;
}
// Get the "idle path" coordinates loaded from the map.
string idlePath;
if (info.TryGetValue("path", out idlePath))
{
string[] idlePathPoints = Parse.List(idlePath);
foreach (string pathPoint in idlePathPoints)
{
Point? point = Parse.Coordinates(pathPoint);
if (point != null) mIdlePath.Add(point.Value);
}
}
// Start doing something...
//StartPacing();
}
public void DefaultAction()
{
mState = AiState.Standing;
}
public void Chasing(Point Chase)
{
Chasing(Chase.X, Chase.Y);
}
///
/// Call this to switch the monster AI state to Chasing and set up
/// the initial paths. A path to .
///
public void Chasing(int X, int Y)
{
mState = AiState.Chasing;
// Determine the best (closest) waypoint to start at.
// We may not be on the path, so we have to walk to get on it.
/*
mIdlePathIndex = 0;
int closest = int.MaxValue;
for (int i = 0; i < mIdlePath.Count; i++)
{
int distance = PathFinder.GetManhattanDistance(Coordinates, mIdlePath[i]);
if (distance < closest)
{
mIdlePathIndex = i;
closest = distance;
}
}
*/
// Find the path to get to the closest waypoint.
if (pathFinder == null)
pathFinder = new PathFinder(mGame.Grid);
mPath = new List(32);
mPath.Add(Coordinates);
List path = pathFinder.GetPath(mMotion.Coordinates, new Point(X,Y));
if (path != null)
{
mPath.AddRange(path);
//mPath.Add(mIdlePath[mIdlePathIndex]);
}
mPathIndex = 0;
}
///
/// Call this to switch the monster AI state to pacing and set up
/// the initial paths. The monster will start following the path it
/// was defined with in the map file.
///
public void StartPacing()
{
mState = AiState.Pacing;
if (mIdlePath.Count == 0) return;
// Determine the best (closest) waypoint to start at.
// We may not be on the path, so we have to walk to get on it.
mIdlePathIndex = 0;
int closest = int.MaxValue;
for (int i = 0; i < mIdlePath.Count; i++)
{
int distance = PathFinder.GetManhattanDistance(Coordinates, mIdlePath[i]);
if (distance < closest)
{
mIdlePathIndex = i;
closest = distance;
}
}
// Find the path to get to the closest waypoint.
PathFinder pathFinder = new PathFinder(mGame.Grid);
mPath = new List(32);
mPath.Add(Coordinates);
List path = pathFinder.GetPath(mMotion.Coordinates, mIdlePath[mIdlePathIndex]);
if (path != null)
{
mPath.AddRange(path);
mPath.Add(mIdlePath[mIdlePathIndex]);
}
mPathIndex = 0;
}
Direction GetDirectionToNextCell()
{
if (mPathIndex >= mPath.Count)
{
mState = AiState.Standing;
}
// We need to make sure out direction is set to the next cell
// we want to be. If our current coordinates match that, we need
// to change our direction to get to the next cell.
if (mPath[mPathIndex % mPath.Count] == mMotion.Coordinates)
{
mPathIndex++;
mPathDirection = MovementManager.GetDirection(mMotion.Coordinates, mPath[mPathIndex % mPath.Count]);
}
return mPathDirection;
}
#region IMonster Members
///
/// I don't know what this is for.
///
public bool visible
{
get { throw new NotImplementedException(); }
}
#endregion
#region ICharacter Members
///
/// Load the monster's content. This is called by the map when
/// the game requests the entities.
///
/// The zaphnod.
public void LoadContent(ContentManager contentManager)
{
mTexture = contentManager.Load("menuItem");
}
///
/// Update the monster's state. This should be called by the game
/// every "frame" (whenever the game is updating its state). In this
/// simple monster, all we need to do is update the motion manager.
///
///
public void Update(TimeSpan timeSpan)
{
switch (mState)
{
case AiState.Pacing:
case AiState.Chasing:
mMotion.Update(timeSpan, GetDirectionToNextCell());
break;
case AiState.Standing:
case AiState.Dazed:
case AiState.Fighting:
case AiState.Retreating:
break;
}
}
///
/// Draw the monster. We just ask the map for our screen position,
/// passing it the position which the motion manager keeps track of.
///
/// The
public void Draw(SpriteBatch spriteBatch)
{
Rectangle position = mGame.State.Map.GetRectangleFromCoordinates(mMotion.Position);
spriteBatch.Draw(mTexture, position, Color.White);
}
///
/// A monster should keep track of its health. This one doesn't.
///
public int Health
{
get { return this.health; }
}
///
/// This monster is invincible.
///
///
public void causeDamageTo(int amount)
{
this.health -= amount;
}
public bool IsCollidable { get { return true; } }
///
/// Get the smoothed position.
///
public Vector2 Position { get { return mMotion.Position; } }
///
/// Get the grid coordinates.
///
public Point Coordinates {
get { return mMotion.Coordinates; }
set { mMotion = new MovementManager(value, mMotion.Speed); }
}
///
/// Get the entity identifier.
///
public char Identifier { get { return mId; } }
#endregion
#region Private Variables
Game mGame;
char mId;
MovementManager mMotion;
PathFinder pathFinder;
List mIdlePath = new List(); // List of waypoints that we got from the map.
int mIdlePathIndex; // Index to the waypoint we're heading for.
List mPath; // List of cells in the path between the position between where
// we started and the waypoint we're heading for.
int mPathIndex; // Index to the cell we're heading for.
Direction mPathDirection; // The direction between our current position and the place we're going.
AiState mState; // What is the monster doing?
Texture2D mTexture; // Obvious.
#endregion
}
}