using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; namespace SemiColinGames { class IdleState : IState { private readonly NPC npc; private float timeInState = 0; public IdleState(NPC npc) { this.npc = npc; } public void Enter() { timeInState = 0; } public string Update(float modelTime, SneakWorld world, Object _) { timeInState += modelTime; if (timeInState > 1.0f) { npc.Facing *= -1; return "run"; } return null; } } class RunState : IState { private readonly NPC npc; public RunState(NPC npc) { this.npc = npc; } public void Enter() {} public string Update(float modelTime, SneakWorld world, Object _) { float moveSpeed = 120; float desiredX = npc.Position.X + moveSpeed * npc.Facing * modelTime; float testPoint = desiredX + npc.Box.HalfSize.X * npc.Facing; AABB npcBox = new AABB( new Vector2(testPoint, npc.Position.Y + 1), new Vector2(1, npc.Box.HalfSize.Y)); 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 { private readonly Sprite sprite; private readonly Vector2 spriteCenter; private readonly Vector2 eyeOffset = new Vector2(4, -9); private readonly FSM fsm; private readonly Vector2 halfSize = new Vector2(11, 24); public NPC(Vector2 position, int facing) { sprite = Sprites.Executioner; spriteCenter = new Vector2( sprite.Width / 2, sprite.Height - halfSize.Y - sprite.GroundPadding); Position = position; Box = new AABB(Position, halfSize); Facing = facing; fsm = new FSM("run", new Dictionary> { { "idle", new IdleState(this) }, { "run", new RunState(this) } }); } public int Facing; public Vector2 Position; public AABB Box { get; private set; } public Vector2 EyePosition { get { return Vector2.Add(Position, 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, SneakWorld world) { fsm.Update(modelTime, world, null); Box = new AABB(Position, halfSize); Debug.AddRect(Box, Color.White); } public void Draw(SpriteBatch spriteBatch) { Rectangle textureSource = sprite.GetTextureSource(fsm.StateName, Clock.ModelTime.TotalSeconds); SpriteEffects effect = Facing == 1 ? SpriteEffects.None : SpriteEffects.FlipHorizontally; Color color = Color.White; spriteBatch.Draw(Textures.Executioner.Get, Vectors.Round(Position), textureSource, color, 0f, spriteCenter, Vector2.One, effect, 0f); } } }