using System.Collections.Generic; using Microsoft.Xna.Framework; using V3.Data; using V3.Map; namespace V3.Objects.Movement { // TODO: Rename the class. Current name is unfitting. (But what is fitting?) /// /// Movement scheme for moving an object with the pathfinder. /// public class PlayerMovement : IMovable { private const int CellHeight = Constants.CellHeight; private const int CellWidth = Constants.CellWidth; private const float SpeedModifier = 0.25f; private List mPath; private int mStep; private Vector2 mLastMovement; public bool IsMoving { get; private set; } /// /// Calculates a path without collisions to desired destination. /// /// Pathfinder to use. /// Current position in pixel. /// Destination in pixel. public void FindPath(Pathfinder pathfinder, Vector2 position, Vector2 destination) { mStep = 0; mPath = pathfinder.FindPath(new Vector2((int)(position.X / CellWidth), (int)(position.Y / CellHeight)), new Vector2((int)(destination.X / CellWidth), (int)(destination.Y / CellHeight))); IsMoving = mPath.Count > 0; } /// /// Uses pathfinder to for steady movement to new transition. /// /// Current position in pixel. /// Movement speed of the creature. /// Normalized vector * speed which represents a small step in the direction of desired destination.( public virtual Vector2 GiveNewPosition(Vector2 currentPosition, int speed) { Vector2 nextPosition = mPath[mStep]; Vector2 newPosition = nextPosition - currentPosition; newPosition.Normalize(); float distanceToDestination = Vector2.Distance(nextPosition, currentPosition); if (distanceToDestination < SpeedModifier * speed) { if (mStep == mPath.Count - 1) { IsMoving = false; } else { mStep++; } } mLastMovement = newPosition; return newPosition * SpeedModifier * speed; } /// /// Calculates the direction the creature is looking when moving. /// public MovementDirection GiveMovementDirection() { // |\ // |α\ α == 22.5° // b| \ 1 β == 67.5° // | β\ // ────── // a const float b = 0.92f; // b == sin β const float a = 0.38f; // a == sin α Vector2 direction = mLastMovement; MovementDirection movementDirection; if (direction.X < -b) { movementDirection = MovementDirection.W; } else if (direction.X > b) { movementDirection = MovementDirection.O; } else if (direction.Y > 0) { if (direction.X < -a) { movementDirection = MovementDirection.SW; } else if (direction.X > a) { movementDirection = MovementDirection.SO; } else { movementDirection = MovementDirection.S; } } else { if (direction.X < -a) { movementDirection = MovementDirection.NW; } else if (direction.X > a) { movementDirection = MovementDirection.NO; } else { movementDirection = MovementDirection.N; } } return movementDirection; } /// /// Save the movement data to a MovementData object. /// /// the MovementData object with the current status public MovementData SaveData() { var data = new MovementData(); data.IsMoving = IsMoving; if (IsMoving) { data.Path = mPath; data.Step = mStep; data.LastMovement = mLastMovement; } return data; } /// /// Restore the movement state from the given data. /// /// the state of the movement to restore public void LoadData(MovementData movementData) { if (movementData == null) return; IsMoving = movementData.IsMoving; if (IsMoving) { mPath = movementData.Path; mStep = movementData.Step; mLastMovement = movementData.LastMovement; } } } }