From ced3d03bdb3ce866d832e03fb212865140905a9a Mon Sep 17 00:00:00 2001 From: Thomas Leyh Date: Sun, 24 Jul 2016 08:14:18 +0200 Subject: Add project files. --- V3/Map/AbstractLayer.cs | 259 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 V3/Map/AbstractLayer.cs (limited to 'V3/Map/AbstractLayer.cs') diff --git a/V3/Map/AbstractLayer.cs b/V3/Map/AbstractLayer.cs new file mode 100644 index 0000000..efc626d --- /dev/null +++ b/V3/Map/AbstractLayer.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Camera; +using V3.Objects; + +namespace V3.Map +{ + /// + /// A drawable map layer usually created from a Tiled map file. + /// + public abstract class AbstractLayer + { + private const int CellHeight = Constants.CellHeight; + private const int CellWidth = Constants.CellWidth; + + private readonly int mTileWidth; + private readonly int mTileHeight; + private readonly int mMapWidth; + private readonly int mMapHeight; + private readonly List mTextureObjects = new List(); + private readonly int[,] mTileArray; + private readonly SortedList mTilesets; + + protected AbstractLayer(int tileWidth, + int tileHeight, + int mapWidth, + int mapHeight, + int[,] tileArray, + SortedList tilesets) + { + mTileWidth = tileWidth; + mTileHeight = tileHeight; + mMapWidth = mapWidth; + mMapHeight = mapHeight; + mTilesets = tilesets; + if (tileArray.Length == mapWidth * mapHeight) + { + mTileArray = tileArray; + } + else + { + throw new Exception("Error constructing map layer. Map size does not fit the map description."); + } + } + + /// + /// Create the map objects according to the given map array. + /// + public void CreateObjects() + { + var firstgridList = mTilesets.Keys; + for (int i = 0; i < mMapHeight; i++) + { + int horizontalOffset = (i % 2 == 0) ? (-mTileWidth / 2) : 0; + for (int j = 0; j < mMapWidth; j++) + { + int tileId = mTileArray[i, j]; + // Checks which tileset needs to be used for the specific tile ID at position [i, j] + for (int k = firstgridList.Count - 1; k >= 0; k--) + { + if (tileId == 0) + { + // This does generally nothing. But you can overwrite GenerateNullObject() for other behaviour. + TextureObject objectToInsert = GenerateNullObject(); + if (objectToInsert != null) + { + mTextureObjects.Add(objectToInsert); + } + break; + } + else if (tileId >= firstgridList[k]) + { + Tileset tileset = mTilesets.Values[k]; + int firstgrid = firstgridList[k]; + Point position = SelectPosition(j, i, horizontalOffset); + Point textureSize = new Point(tileset.TileWidth, tileset.TileHeight); + Point destination = SelectDestination(j, i, horizontalOffset, tileset.OffsetX, tileset.TileHeight, tileset.OffsetY); + Point source = SelectSource(tileId, firstgrid, tileset.TileWidth, tileset.TileHeight, tileset.Columns); + IGameObject objectToInsert; + if (tileset.Name == "houses_rear" || tileset.Name == "houses_front") + { + if (source.Y < textureSize.Y * 2) + { + int initialDamage = 0; + if (source.X / textureSize.X == 1) + { + initialDamage = 50; + } + else if (source.X / textureSize.X == 2) + { + initialDamage = 80; + } + IBuilding building = new Woodhouse(position.ToVector2(), new Rectangle(destination, textureSize), tileset.Name, source.Y % 384 == 0 ? BuildingFace.SW : BuildingFace.NO); + building.TakeDamage(initialDamage); + objectToInsert = building; + } + else + { + int initialDamage = 0; + if (source.X / textureSize.X == 1) + { + initialDamage = 60; + } + else if (source.X / textureSize.X == 2) + { + initialDamage = 100; + } + IBuilding building = new Forge(position.ToVector2(), new Rectangle(destination, textureSize), tileset.Name, source.Y % 384 == 0 ? BuildingFace.SW : BuildingFace.NO); + building.TakeDamage(initialDamage); + objectToInsert = building; + } + } + else if (tileset.Name == "castle") + { + IBuilding building = new Objects.Castle(position.ToVector2(), new Rectangle(destination, textureSize), tileset.Name, BuildingFace.SW); + objectToInsert = building; + } + else + { + objectToInsert = new TextureObject(position, + destination, + textureSize, + source, + tileset.Name); + } + mTextureObjects.Add(objectToInsert); + break; + } + } + } + } + } + + protected virtual TextureObject GenerateNullObject() + { + return null; + } + + /// + /// Loads the image files needed for drawing the tilesets. + /// + /// Content manager used for loading the ressources. + public void LoadContent(ContentManager contentManager) + { + mTextureObjects.ForEach(o => o.LoadContent(contentManager)); + } + + /// + /// Draws only the parts of the map which are visible. More efficient than the other Draw-Method. + /// Not very robust and maybe does not work correctly most layers. + /// This is because of gaps in the list of game objects. + /// + /// Sprite batch used. + /// Needed to tell which objects of the map are looked upon. + public void Draw(SpriteBatch spriteBatch, ICamera camera) + { + int tilesHorizontal = camera.ScreenSize.X / mTileWidth; + int tilesVertical = camera.ScreenSize.Y * 2 / mTileHeight; + int horizontalStart = camera.ScreenRectangle.X / mTileWidth; + int verticalStart = camera.ScreenRectangle.Y * 2 / mTileHeight; + /* + for (int i = 0; i < tilesVertical; i++) + { + for (int j = 0; j < tilesHorizontal; j++) + { + mTextureObjects[horizontalStart + j].Draw(spriteBatch); + } + } + */ + for (int j = 0; j < tilesVertical + 2; j++) + { + for (int i = 0; i < tilesHorizontal + 2; i++) + { + int index = i + horizontalStart + (j + verticalStart) * mMapWidth; + if (index < mTextureObjects.Count) + { + mTextureObjects[index].Draw(spriteBatch); + } + } + } + } + + /// + /// Extract a collision grid from the map layer. Used in pathfinding. + /// + /// A two dimensional boolean collision grid. + public bool[,] ExtractCollisions() + { + int gridHeight = (mMapHeight - 1) * mTileHeight/ CellHeight / 2; + int gridWidth = (mMapWidth - 1) * mTileWidth / CellWidth; + bool[,] collisionGrid = new bool[gridHeight, gridWidth]; + var firstgridList = mTilesets.Keys; + for (int i = 0; i < mMapHeight; i++) + { + for (int j = 0; j < mMapWidth; j++) + { + int tileId = mTileArray[i, j]; + for (int k = firstgridList.Count - 1; k >= 0; k--) + { + if (tileId >= firstgridList[k]) + { + Tileset tileset = mTilesets.Values[k]; + int firstgrid = firstgridList[k]; + tileId -= firstgrid; + bool[,] collisionData; + // Is there even collision data for the specific tile ID? + if (tileset.TileCollisions.TryGetValue(tileId, out collisionData)) + { + int cellOffset = (i % 2 == 0 ? -mTileWidth / 2 : 0) / CellWidth; + int cellsHorizontal = mTileWidth / CellWidth; + int cellsVertical = mTileHeight / CellHeight; + int iStart = (i - 1) * cellsVertical / 2 + cellsVertical - tileset.CollisionHeight + tileset.OffsetY / CellHeight; + int jStart = j * cellsHorizontal + cellOffset + tileset.OffsetX / CellWidth; + for (int iData = 0; iData < tileset.CollisionHeight; iData++) + { + for (int jData = 0; jData < tileset.CollisionWidth; jData++) + { + // Do we even need to update collisionGrid? + if (iStart + iData >= 0 && iStart + iData < gridHeight && jStart + jData >= 0 && jStart + jData < gridWidth && + collisionData[iData, jData] && !collisionGrid[iStart + iData, jStart + jData]) + { + collisionGrid[iStart + iData, jStart + jData] = collisionData[iData, jData]; + } + } + } + } + break; + } + } + } + } + return collisionGrid; + } + + public List ExtractObjects() + { + return mTextureObjects; + } + + private Point SelectDestination(int x, int y, int xOffset, int tileXOffset, int tileHeight, int tileYOffset) + { + return new Point(x * mTileWidth + xOffset + tileXOffset, + (y - 1) * (mTileHeight / 2) - tileHeight + mTileHeight + tileYOffset); + } + + private Point SelectSource(int tileId, int firstgrid, int tileWidth, int tileHeight, int tilesPerRow) + { + return new Point((tileId - firstgrid) % tilesPerRow * tileWidth, (tileId - firstgrid) / tilesPerRow * tileHeight); + } + + private Point SelectPosition(int x, int y, int xOffset) + { + return new Point(x * mTileWidth + xOffset + mTileWidth / 2, y * (mTileHeight / 2)); + } + } +} \ No newline at end of file -- cgit v1.2.1