/// <summary> /// Updates the player. /// </summary> /// <param name="gameTime"> Provides a snapshot of timing values. </param> /// <param name="level"> The level in progress. </param> public override void Update(GameTime gameTime, Level level) { foreach (var playerUnit in this.PlayerUnits) { playerUnit.Update(gameTime); } // Stupid AI // TODO: Improve if (gameTime.TotalGameTime.Seconds % 10 == 0) { this.IsTurnFinished = true; } }
/// <summary> /// Draws the unit as a player unit /// </summary> /// <param name="gameTime"> A snapshot of timing values. </param> /// <param name="level"> The current level. </param> /// <param name="playerUnit"> The unit </param> private void DrawPlayerUnit(GameTime gameTime, Level level, Unit playerUnit) { var unitOffsetX = (Engine.TileHeight / 2) - (playerUnit.Sprite.Height / 2); var unitOffsetY = (Engine.TileWidth / 2) - (playerUnit.Sprite.Width / 2); // Converts the position of the unit to a vector that represents a // location on the gamescreen. var vect = new Vector2( (playerUnit.Sprite.Position.Y * Engine.TileHeight) - level.Camera.Position.X + unitOffsetY, (playerUnit.Sprite.Position.X * Engine.TileWidth) - level.Camera.Position.Y + unitOffsetX); // Draws the unit. playerUnit.Draw( gameTime, Game1.SpriteBatch, vect); }
/// <summary> /// Draws the unit as a npc unit /// </summary> /// <param name="gameTime"> A snapshot of timing values. </param> /// <param name="level"> The current level. </param> /// <param name="npcUnit"> The unit </param> private void DrawNPCUnit(GameTime gameTime, Level level, Unit npcUnit) { // Draws the NPC is Fog of War is not enabled. if (!this.FowEnabled) { var unitOffsetX = (Engine.TileHeight / 2) - (npcUnit.Sprite.Height / 2); var unitOffsetY = (Engine.TileWidth / 2) - (npcUnit.Sprite.Width / 2); // Converts the position of the unit to a vector that represents a // location on the gamescreen. var vect = new Vector2( (npcUnit.Sprite.Position.Y * Engine.TileHeight) - level.Camera.Position.X + unitOffsetY, (npcUnit.Sprite.Position.X * Engine.TileWidth) - level.Camera.Position.Y + unitOffsetX); // Draws the unit. npcUnit.Draw( gameTime, Game1.SpriteBatch, vect); return; } // If FoW is enabled and the square the npc unit is on is visible, draw the unit. if (this.IsVisible(npcUnit.Location.X, npcUnit.Location.Y)) { var unitOffsetX = (Engine.TileHeight / 2) - (npcUnit.Sprite.Height / 2); var unitOffsetY = (Engine.TileWidth / 2) - (npcUnit.Sprite.Width / 2); // Converts the position of the unit to a vector that represents a // location on the gamescreen. var vect = new Vector2( (npcUnit.Sprite.Position.Y * Engine.TileHeight) - level.Camera.Position.X + unitOffsetY, (npcUnit.Sprite.Position.X * Engine.TileWidth) - level.Camera.Position.Y + unitOffsetX); // Draws the unit. npcUnit.Draw( gameTime, Game1.SpriteBatch, vect); } }
/// <summary> /// Draws the Fog of War on the map. /// </summary> /// <param name="level"> The level in progress. </param> private void DrawFoW(Level level) { // Finds the square that is to the top-left. var firstSquare = new Vector2( level.Camera.Position.X / Engine.TileWidth, level.Camera.Position.Y / Engine.TileHeight); var firstX = (int)firstSquare.X; var firstY = (int)firstSquare.Y; // Figured out what how far the tiles have been offset. var squareOffset = new Vector2( level.Camera.Position.X % Engine.TileWidth, level.Camera.Position.Y % Engine.TileHeight); var offsetX = (int)squareOffset.X; var offsetY = (int)squareOffset.Y; // Iterates over all tiles that are to be drawn on the screen. Ignores all tiles that are // outside the bounds of the scrren. for (int y = 0; y <= level.Camera.ViewportRectangle.Width / Engine.TileWidth; y++) { for (int x = 0; x <= level.Camera.ViewportRectangle.Height / Engine.TileHeight; x++) { // Finds the actual location int currentX = x + firstX < this.MapWidth ? x + firstX : this.MapWidth - 1; int currentY = y + firstY < this.MapHeight ? y + firstY : this.MapHeight - 1; // If the tile is not visible by a unit... if (!this.IsVisible(currentY, currentX)) { // ...draw the Fog of War texture on it. Game1.SpriteBatch.Draw( Engine.FoWTexture, new Rectangle( (x * Engine.TileWidth) - offsetX, (y * Engine.TileHeight) - offsetY, Engine.TileWidth, Engine.TileHeight), Color.White); } } } }
/// <summary> /// Adds FoW to the area surrounding the unit. /// Mainly used when a unit is moved. /// </summary> /// <param name="unit"> The unit to add FoW around. </param> /// <param name="level"> The level in progress. </param> private void AddFoW(Unit unit, Level level) { if (this.FowEnabled) { for (int x = 0 - unit.ViewRange; x < unit.ViewRange + 1; x++) { for (int y = 0 - unit.ViewRange; y < unit.ViewRange + 1; y++) { if (this.dataMap.WithinViewAndMap(x, y, unit)) { this.SetVisibility(unit.Location.X + x, unit.Location.Y + y, false); } } } foreach (var playerUnit in level.PlayerController.CurrentPlayer.PlayerUnits) { playerUnit.HasProcessedFoW = false; this.RemoveFoW(playerUnit); } } }
/// <summary> /// Calls the methods that are needed for when a unit is moved away. /// </summary> /// <param name="unit"> The unit that is moving. </param> /// <param name="level"> The level in progress. </param> public void MoveUnitAway(Unit unit, Level level) { this.SetOccupationStatus(unit.Location.X, unit.Location.Y, false); if (this.PersistentFoW) { if (unit is PlayerUnit) { this.AddFoW(unit, level); } } }
/// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> /// <param name="level"> The level in progress. </param> public void DrawMap(GameTime gameTime, Level level) { this.DrawTiles(level); this.DrawUnits(gameTime, level); if (this.FowEnabled) { this.DrawFoW(level); } }
/// <summary> /// Updates the player. /// </summary> /// <param name="gameTime"> Provides a snapshot of timing values. </param> /// <param name="level"> The level in progress. </param> public abstract void Update(GameTime gameTime, Level level);
/// <summary> /// Updates the Controller. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> /// <param name="level">The level currently in progress.</param> public void Update(GameTime gameTime, Level level) { foreach (var player in this.players) { player.Update(gameTime, level); } if (this.currentPlayer.Value.IsTurnFinished) { this.currentPlayer.Value.EndTurn(); this.currentPlayer = this.currentPlayer.Next ?? this.players.First; this.currentPlayer.Value.StartTurn(); } }
/// <summary> /// Checks if a unit belonging to the player is at the clicked location /// and selects it if there is. /// </summary> /// <param name="level"> The level. </param> private void SelectUnit(Level level) { if (InputHandler.LeftMouseClicked() && !this.unitSelected && !this.justClicked) { // Note! MouseState.X is the horizontal position and MouseState.Y is the vertical position. // I want Y to be the horizontal coordinate (the width) and X to be the vertical coordinate // (the height), so tileY is using the X values and tileX is using the Y values. var tileY = (int)(InputHandler.MouseState.X + level.Camera.Position.X) / Engine.TileHeight; var tileX = (int)(InputHandler.MouseState.Y + level.Camera.Position.Y) / Engine.TileWidth; foreach (var playerUnit in this.PlayerUnits) { // Checks if the unit matches the tile that was clicked. if (playerUnit.Location.X == tileX && playerUnit.Location.Y == tileY) { // Selects the unit and thereby changes the animation of the unit. playerUnit.Select(); this.unitSelected = true; this.selectedUnit = playerUnit; // Finds the area which the unit can walk to. level.LevelMap.MarkValidMoves(this.selectedUnit); } } // Ensures that other parts in the update method won't be triggered. this.justClicked = true; } }
/// <summary> /// Updates the player. /// </summary> /// <param name="gameTime"> Provides a snapshot of timing values. </param> /// <param name="level"> The level in progress. </param> public override void Update(GameTime gameTime, Level level) { foreach (var playerUnit in this.PlayerUnits) { playerUnit.Update(gameTime); } if (!this.IsCurrentPlayer) { return; } this.justClicked = false; // Just testing stuff if (InputHandler.KeyPressed(Keys.K)) { var random = new Random(); var toChange = random.Next(this.PlayerUnits.Count); var unit = this.PlayerUnits[toChange]; unit.CurrentHealth = unit.CurrentHealth / 2; this.PlayerUnits.Remove(unit); level.LevelMap.MoveUnitAway(unit, level); } this.SelectUnit(level); this.DeselectUnit(level); this.MoveUnit(level); this.EndPlayersTurn(level); }
/// <summary> /// Moves the selected unit to the clicked location, assuming the location /// is within range of the unit. /// </summary> /// <param name="level"> The level. </param> private void MoveUnit(Level level) { if (InputHandler.LeftMouseClicked() && this.unitSelected && !this.justClicked) { // Note! MouseState.X is the horizontal position and MouseState.Y is the vertical position. // I want Y to be the horizontal coordinate (the width) and X to be the vertical coordinate // (the height), so tileY is using the X values and tileX is using the Y values. var tileY = (int)(InputHandler.MouseState.X + level.Camera.Position.X) / Engine.TileHeight; var tileX = (int)(InputHandler.MouseState.Y + level.Camera.Position.Y) / Engine.TileWidth; var tempVector = new Vector(tileX, tileY); // Checks if the chosen tile is occupied or not. if (!level.LevelMap.IsOccupied(tileX, tileY) && this.selectedUnit.CanTraverse(level.LevelMap.GetCollisionType(tileX, tileY)) && this.selectedUnit.PointWithinMoveRange(tempVector)) { var pathToTarget = level.LevelMap.FindShortestPathWithinReach(this.selectedUnit, tempVector).Count; if (pathToTarget != 0 && pathToTarget <= this.selectedUnit.MoveRange) { // Removes the unit from the list, as we need to change the // position of the unit. this.PlayerUnits.Remove(this.selectedUnit); // Notifies the map that the unit is disappearing from its current // location. level.LevelMap.MoveUnitAway(this.selectedUnit, level); // Changes the unit's location. this.selectedUnit.Location = (Vector)tempVector.Clone(); this.selectedUnit.MoveUnit(); // Notifies the map that the unit has arrived at its target // location and adds the unit to the unit list again. level.LevelMap.MoveUnitToNewPosition(this.selectedUnit); this.PlayerUnits.Add(this.selectedUnit); this.unitSelected = false; this.selectedUnit = null; } } // Ensures that other parts in the update method won't be triggered. this.justClicked = true; } }
/// <summary> /// Ends the player's turn /// </summary> /// <param name="level"> The level. </param> private void EndPlayersTurn(Level level) { if (InputHandler.KeyPressed(Keys.G)) { this.IsTurnFinished = true; this.selectedUnit.MoveUnit(); level.LevelMap.MoveUnitToNewPosition(this.selectedUnit); this.unitSelected = false; this.selectedUnit = null; // Ensures that other parts in the update method won't be triggered. this.justClicked = true; } }
/// <summary> /// Deselects the currently selected unit. /// </summary> /// <param name="level"> The level. </param> private void DeselectUnit(Level level) { if (InputHandler.RightMouseClicked() && this.unitSelected && !this.justClicked) { level.LevelMap.ClearValidMoves(); this.selectedUnit.Deselect(); this.unitSelected = false; this.selectedUnit = null; // Ensures that other parts in the update method won't be triggered. this.justClicked = true; } }
/// <summary> /// Draws the tiles on the DataMap. /// </summary> /// <param name="level"> The level in progress. </param> private void DrawTiles(Level level) { // Finds the square that is to the top-left. var firstSquare = new Vector2( level.Camera.Position.X / Engine.TileWidth, level.Camera.Position.Y / Engine.TileHeight); var firstX = (int)firstSquare.X; var firstY = (int)firstSquare.Y; // Figured out what how far the tiles have been offset. var squareOffset = new Vector2( level.Camera.Position.X % Engine.TileWidth, level.Camera.Position.Y % Engine.TileHeight); var offsetX = (int)squareOffset.X; var offsetY = (int)squareOffset.Y; // Iterates over all layers in mapLayers. foreach (var mapLayer in this.mapLayers) { // Ignores the collision layer. if (mapLayer.LayerName.Equals("collision")) { continue; } // Iterates over all tiles that are to be drawn on the screen. Ignores all tiles that are // outside the bounds of the scrren. for (int y = 0; y <= level.Camera.ViewportRectangle.Width / Engine.TileWidth; y++) { for (int x = 0; x <= level.Camera.ViewportRectangle.Height / Engine.TileHeight; x++) { // Finds the actual tile int currentX = x + firstX < mapLayer.Width ? x + firstX : mapLayer.Width - 1; int currentY = y + firstY < mapLayer.Height ? y + firstY : mapLayer.Height - 1; Tile tile = mapLayer.GetTile(currentX, currentY); // If the tile is transparent, don't bother drawing it. if (tile.TileID == 0) { continue; } // Draws the tile. Game1.SpriteBatch.Draw( this.tilesets[tile.TileSet].Texture, new Rectangle( (x * Engine.TileWidth) - offsetX, (y * Engine.TileHeight) - offsetY, Engine.TileWidth, Engine.TileHeight), this.tilesets[tile.TileSet].SourceRectangles[tile.TileID], Color.White); } } } // If a unit is selected, the validMovesList is not null. if (this.validMovesList != null) { // Iterates over all vector2d in the valieMovesList foreach (var vector2 in this.validMovesList) { // Converts the vector to a vector that represents the position on // the screen. var vect = new Vector2( (vector2.Y * Engine.TileWidth) - level.Camera.Position.X, (vector2.X * Engine.TileHeight) - level.Camera.Position.Y); // Draws the location with a semi-transparent blue square, indicating that // the currently selected unit can walk to those tiles. Game1.SpriteBatch.Draw( Engine.ValidMoveTexture, vect, Color.White); } } }
/// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); // Makes a rectangle that is used to tell the Camera how much of the game // it is supposed to show at any given time. var screenRectangle = new Rectangle(0, 0, this.graphics.PreferredBackBufferHeight, this.graphics.PreferredBackBufferWidth); // Loads the texture for Fog of War and Valid Move, which are used during the game. // Instead of saving it in the tilemap, it is saved with the Engine, as both of them // are tilesets consisting of only one tile. No point in saving them as a full tileset in the map. Engine.FoWTexture = this.Content.Load<Texture2D>(@"Textures\TileSets\fow_of_war"); Engine.ValidMoveTexture = this.Content.Load<Texture2D>(@"Textures\TileSets\move_range"); Font = this.Content.Load<SpriteFont>(@"Fonts\OwnFont"); var tempMap = this.mapLoader.LoadTmxFile("Test_1.tmx", this); tempMap.FowEnabled = true; tempMap.PersistentFoW = true; var tempPlayerUnits = new List<Unit>(); var tempNPCUnits = new List<Unit>(); // Makes an AnimatedSprite from a spritesheet, makes a PlayerUnit from it and // adds it to the playerUnits list. var sprite = this.MakeSprite("Ally", "Lin28px", 28, 28); var playerUnit = new PlayerUnit(Unit.GenerateUniqueID(tempPlayerUnits), "Akai", new Vector(5, 3), sprite, new BladesmasterClass()); tempPlayerUnits.Add(playerUnit); sprite = this.MakeSprite("Ally", "FemaleAssassin28px", 28, 28); playerUnit = new PlayerUnit(Unit.GenerateUniqueID(tempPlayerUnits), "Kitai", new Vector(5, 2), sprite, new AssassinClass()); tempPlayerUnits.Add(playerUnit); sprite = this.MakeSprite("Ally", "FlyingUnit32px", 32, 32); playerUnit = new PlayerUnit(Unit.GenerateUniqueID(tempPlayerUnits), "Flyer", new Vector(9, 10), sprite, new FlyingUnitClass()); tempPlayerUnits.Add(playerUnit); sprite = this.MakeSprite("Enemy", "FlyingUnit32px", 32, 32); var enemyUnit = new NPCUnit(Unit.GenerateUniqueID(tempNPCUnits), "Flyer", new Vector(10, 10), sprite, new FlyingUnitClass()); tempNPCUnits.Add(enemyUnit); tempMap.LoadUnits(new List<Unit>(tempPlayerUnits)); tempMap.LoadUnits(new List<Unit>(tempNPCUnits)); this.CurrentLevel = new Level( new Camera(screenRectangle), tempMap); this.CurrentLevel.AddPlayer(new PlayerHuman(tempPlayerUnits)); this.CurrentLevel.AddPlayer(new PlayerNPC(tempNPCUnits)); }
/// <summary> /// Draws the units on the DataMap. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> /// <param name="level"> The level in progress. </param> private void DrawUnits(GameTime gameTime, Level level) { // Iterates over every player in the level's playercontroller // and draws the units belonging to each player. foreach (var player in level.PlayerController.Players) { foreach (var unit in player.PlayerUnits) { if (unit is PlayerUnit) { this.DrawPlayerUnit(gameTime, level, unit); } if (unit is NPCUnit) { this.DrawNPCUnit(gameTime, level, unit); } } } }
/// <summary> /// Updates the camera by responding to user input. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> /// <param name="level"> The level in progress. </param> public void Update(GameTime gameTime, Level level) { // Moves the camera to the left, but makes sure it does nto leave the screen. if (InputHandler.KeyDown(Keys.Left)) { this.position.X = MathHelper.Clamp( this.Position.X - this.speed, 0, (level.LevelMap.MapWidth - Engine.SquaresAcross) * Engine.TileWidth); } // Moves the camera to the right, but makes sure it does nto leave the screen. if (InputHandler.KeyDown(Keys.Right)) { this.position.X = MathHelper.Clamp( this.Position.X + this.speed, 0, (level.LevelMap.MapWidth - Engine.SquaresAcross) * Engine.TileWidth); } // Moves the camera up, but makes sure it does nto leave the screen. if (InputHandler.KeyDown(Keys.Up)) { this.position.Y = MathHelper.Clamp( this.Position.Y - this.speed, 0, (level.LevelMap.MapHeight - Engine.SquaresDown) * Engine.TileHeight); } // Moves the camera down, but makes sure it does nto leave the screen. if (InputHandler.KeyDown(Keys.Down)) { this.position.Y = MathHelper.Clamp( this.Position.Y + this.speed, 0, (level.LevelMap.MapHeight - Engine.SquaresDown) * Engine.TileHeight); } }