public void Move(SelfMovementContext context) { // get next target based on ghost mode and corresponding movement strategy var currentVertex = Position.ToTile(); var currentTile = context.Map[currentVertex.Y, currentVertex.X]; // check if ghost needs to change the direction if (Position.Equals(currentTile.Position)) { var allowedDirections = context.Map.GetNeighbors(currentVertex) .Where(neighbor => !neighbor.IsWall) .Select(neighbor => Position.ToDirection(neighbor.Position)) .ToList(); // specified direction is not allowed, so stop State = !allowedDirections.Contains(context.GameState.PacManNextTurn) ? State with { Direction = Direction.None }
protected override Task PhysicsStep(IGameContext context, CancellationToken token) { _renderer.Render(_map.ToSprite(new Offset(0, 0))); _collisionDetection .DetectCollisions(_map.PacMan, _map.All) .OfType <IEatable>() .ToList() .ForEach(eatable => { _map.PacMan.Effect(new FoodContext(_eventSink, _map, _gameState, eatable)); eatable.Effect(new FoodContext(_eventSink, _map, _gameState, _map.PacMan)); }); var deadGhostSprites = _map.Ghosts .Where(ghost => ghost.Mode == GhostMode.Dead) .Cast <ISprite>() .ToList(); _map.All .OfType <IRespawnSprite>() .ToList() .ForEach(respawn => { _collisionDetection .DetectCollisions(respawn, deadGhostSprites) .OfType <IGhost>() .ToList() .ForEach(ghost => respawn.Effect(new GhostRespawnContext(ghost))); }); // TODO: do the movement in a separate timers to simulate different speeds var selfMovementContext = new SelfMovementContext(_eventSink, _map, _gameState, _lastUpdateTime); _map.PacMan.Move(selfMovementContext); _map.PacMan.Move(selfMovementContext); _map.Ghosts.ToList().ForEach(ghost => ghost.Move(selfMovementContext)); _lastUpdateTime = DateTime.Now; return(Task.CompletedTask); }
public void Move(SelfMovementContext context) { // get next target based on ghost mode and corresponding movement strategy var currentVertex = Position.ToTile(); var currentTile = context.Map[currentVertex.Y, currentVertex.X]; // check if ghost needs to change the direction if (Position.Equals(currentTile.Position)) { CheckTimeoutBeforeBeingComforted(DateTime.Now); CheckTimeoutBeforeChangingMode(DateTime.Now); var movementContext = new GhostMovementContext(context.EventSink, context.Map, this); var target = _currentMode.Execute(movementContext); var ghostPosition = Position; var ghostDirection = State.Direction; var graph = context.Map; var neighbors = graph.GetNeighbors(currentVertex) .Where(neighbor => !neighbor.IsWall) .ToList(); var allowedDirections = neighbors .Select(neighbor => ghostPosition.ToDirection(neighbor.Position)) .Where(direction => direction != ghostDirection.ToOpposite()) .Where(direction => direction != currentTile.Restriction) .ToList(); if (allowedDirections.Count == 1) { // there is only one way to go/turn - go/turn that way State = State with { Direction = allowedDirections.Single() }; } else if (allowedDirections.Count == 0) { // there were no ways to go/turn, choosing the direction closest to target var targetDirection = neighbors .Select(neighbor => neighbor.Position) .OrderBy(neighbor => neighbor.EuclideanDistance(target)) .First(); State = State with { Direction = ghostPosition.ToDirection(targetDirection) }; } else if (neighbors.Count >= 3) { // current tile is the tile in which we need to decide where to go/turn // TODO: check the direction accroding to the priorities below // Direction.Up, Direction.Left, Direction.Down var targetDirection = allowedDirections .Select(direction => Position.Shift(direction.ToOffset())) .OrderBy(neighbor => neighbor.EuclideanDistance(target)) .First(); State = State with { Direction = ghostPosition.ToDirection(targetDirection) }; } } var nextPosition = Position.Shift(State.Direction.ToOffset()); var afterVertex = nextPosition.ToTile(); var afterTile = context.Map[afterVertex.Y, afterVertex.X]; Position = afterTile.IsWall ? Position : nextPosition; }