using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System.Collections.Generic; namespace SemiColinGames { class IdleState : IState { float timeInState = 0; public void Enter() { timeInState = 0; } public string Update(NPC npc, float modelTime, World world) { timeInState += modelTime; if (timeInState > 1.0f) { npc.Facing *= -1; return "run"; } return null; } } class RunState : IState { public void Enter() {} public string Update(NPC npc, float modelTime, World world) { int moveSpeed = 120; int desiredX = npc.Position.X + (int) (moveSpeed * npc.Facing * modelTime); int testPoint = desiredX + 12 * npc.Facing; // TODO: define the box modularly & correctly. AABB npcBox = new AABB(new Vector2(testPoint, npc.Position.Y), new Vector2(1, 25)); Debug.AddRect(npcBox, Color.Cyan); bool foundBox = false; foreach (AABB box in world.CollisionTargets) { if (box.Intersect(npcBox) != null) { foundBox = true; break; } } if (!foundBox) { return "idle"; } npc.Position.X = desiredX; return null; } } public class NPC { // TODO: load sprite sizes from metadata. private const int spriteWidth = 96; private const int spriteHeight = 82; private const int groundPadding = 7; private readonly Vector2 spriteCenter; private readonly Vector2 eyeOffset = new Vector2(4, -9); private readonly FSM fsm; private AABB physicsBox; private readonly Vector2 halfSize = new Vector2(12, 24); public NPC(Point position, int facing) { Position = position; spriteCenter = new Vector2(spriteWidth / 2, spriteHeight - halfSize.Y - groundPadding); physicsBox = new AABB(position.ToVector2(), halfSize); Facing = facing; fsm = new FSM(new Dictionary> { { "idle", new IdleState() }, { "run", new RunState() } }, "run"); } public int Facing; public Point Position; public Vector2 EyePosition { get { return Vector2.Add( Position.ToVector2(), new Vector2(eyeOffset.X * Facing, eyeOffset.Y)); } } public float VisionRange { get { return 150; } } public float FieldOfView { get { return FMath.DegToRad(120); } } public Vector2 VisionRay { get { return new Vector2(VisionRange * Facing, 0); } } public void Update(float modelTime, World world) { fsm.Update(this, modelTime, world); physicsBox = new AABB(Position.ToVector2(), halfSize); Debug.AddRect(physicsBox, Color.White); } public void Draw(SpriteBatch spriteBatch) { Rectangle textureSource = Sprites.Executioner.GetTextureSource( fsm.StateName, Clock.ModelTime.TotalSeconds); SpriteEffects effect = Facing == 1 ? SpriteEffects.None : SpriteEffects.FlipHorizontally; Color color = Color.White; spriteBatch.Draw(Textures.Executioner.Get, Position.ToVector2(), textureSource, color, 0f, spriteCenter, Vector2.One, effect, 0f); } } }