|
@@ -0,0 +1,362 @@
|
|
|
|
+using System;
|
|
|
|
+using System.Collections.Generic;
|
|
|
|
+using System.Linq;
|
|
|
|
+using Microsoft.Xna.Framework;
|
|
|
|
+using Microsoft.Xna.Framework.Audio;
|
|
|
|
+using Microsoft.Xna.Framework.Content;
|
|
|
|
+using Microsoft.Xna.Framework.Graphics;
|
|
|
|
+using Microsoft.Xna.Framework.Input;
|
|
|
|
+using Microsoft.Xna.Framework.Media;
|
|
|
|
+using System.IO;
|
|
|
|
+using System.Xml.Serialization;
|
|
|
|
+using System.Runtime.Serialization.Formatters.Binary;
|
|
|
|
+
|
|
|
|
+namespace Tile_Engine
|
|
|
|
+{
|
|
|
|
+ public static class TileMap
|
|
|
|
+ {
|
|
|
|
+
|
|
|
|
+ public const int TileWidth = 48;
|
|
|
|
+ public const int TileHeight = 48;
|
|
|
|
+ public const int MapWidth = 160;
|
|
|
|
+ public const int MapHeight = 12;
|
|
|
|
+ public const int MapLayers = 3;
|
|
|
|
+ private const int skyTile = 2;
|
|
|
|
+
|
|
|
|
+ static public MapSquare[][] mapCells =
|
|
|
|
+ CreateJaggedArray(MapWidth, MapHeight);
|
|
|
|
+
|
|
|
|
+ public static bool EditorMode = false;
|
|
|
|
+
|
|
|
|
+ public static SpriteFont spriteFont;
|
|
|
|
+ static private Texture2D tileSheet;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ static public void Initialize(Texture2D tileTexture)
|
|
|
|
+ {
|
|
|
|
+ tileSheet = tileTexture;
|
|
|
|
+ mapCells = CreateJaggedArray(MapWidth, MapHeight);
|
|
|
|
+ for (int x = 0; x < MapWidth; x++)
|
|
|
|
+ {
|
|
|
|
+ for (int y = 0; y < MapHeight; y++)
|
|
|
|
+ {
|
|
|
|
+ for (int z = 0; z < MapLayers; z++)
|
|
|
|
+ {
|
|
|
|
+ mapCells[x][y] = new MapSquare(skyTile, 0, 0, "", true);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ public static int TilesPerRow
|
|
|
|
+ {
|
|
|
|
+ get { return tileSheet.Width / TileWidth; }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static Rectangle TileSourceRectangle(int tileIndex)
|
|
|
|
+ {
|
|
|
|
+ return new Rectangle(
|
|
|
|
+ (tileIndex % TilesPerRow) * TileWidth,
|
|
|
|
+ (tileIndex / TilesPerRow) * TileHeight,
|
|
|
|
+ TileWidth,
|
|
|
|
+ TileHeight);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ static public int GetCellByPixelX(int pixelX)
|
|
|
|
+ {
|
|
|
|
+ return pixelX / TileWidth;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public int GetCellByPixelY(int pixelY)
|
|
|
|
+ {
|
|
|
|
+ return pixelY / TileHeight;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public Vector2 GetCellByPixel(Vector2 pixelLocation)
|
|
|
|
+ {
|
|
|
|
+ return new Vector2(
|
|
|
|
+ GetCellByPixelX((int)pixelLocation.X),
|
|
|
|
+ GetCellByPixelY((int)pixelLocation.Y));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public Vector2 GetCellCenter(int cellX, int cellY)
|
|
|
|
+ {
|
|
|
|
+ return new Vector2(
|
|
|
|
+ (cellX * TileWidth) + (TileWidth / 2),
|
|
|
|
+ (cellY * TileHeight) + (TileHeight / 2));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public Vector2 GetCellCenter(Vector2 cell)
|
|
|
|
+ {
|
|
|
|
+ return GetCellCenter(
|
|
|
|
+ (int)cell.X,
|
|
|
|
+ (int)cell.Y);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public Rectangle CellWorldRectangle(int cellX, int cellY)
|
|
|
|
+ {
|
|
|
|
+ return new Rectangle(
|
|
|
|
+ cellX * TileWidth,
|
|
|
|
+ cellY * TileHeight,
|
|
|
|
+ TileWidth,
|
|
|
|
+ TileHeight);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public Rectangle CellWorldRectangle(Vector2 cell)
|
|
|
|
+ {
|
|
|
|
+ return CellWorldRectangle(
|
|
|
|
+ (int)cell.X,
|
|
|
|
+ (int)cell.Y);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public Rectangle CellScreenRectangle(int cellX, int cellY)
|
|
|
|
+ {
|
|
|
|
+ return Camera.WorldToScreen(CellWorldRectangle(cellX, cellY));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public Rectangle CellSreenRectangle(Vector2 cell)
|
|
|
|
+ {
|
|
|
|
+ return CellScreenRectangle((int)cell.X, (int)cell.Y);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public bool CellIsPassable(int cellX, int cellY)
|
|
|
|
+ {
|
|
|
|
+ MapSquare square = GetMapSquareAtCell(cellX, cellY);
|
|
|
|
+
|
|
|
|
+ if (square == null)
|
|
|
|
+ return false;
|
|
|
|
+ else
|
|
|
|
+ return square.Passable;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public bool CellIsPassable(Vector2 cell)
|
|
|
|
+ {
|
|
|
|
+ return CellIsPassable((int)cell.X, (int)cell.Y);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public bool CellIsPassableByPixel(Vector2 pixelLocation)
|
|
|
|
+ {
|
|
|
|
+ return CellIsPassable(
|
|
|
|
+ GetCellByPixelX((int)pixelLocation.X),
|
|
|
|
+ GetCellByPixelY((int)pixelLocation.Y));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public string CellCodeValue(int cellX, int cellY)
|
|
|
|
+ {
|
|
|
|
+ MapSquare square = GetMapSquareAtCell(cellX, cellY);
|
|
|
|
+
|
|
|
|
+ if (square == null)
|
|
|
|
+ return "";
|
|
|
|
+ else
|
|
|
|
+ return square.CodeValue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public string CellCodeValue(Vector2 cell)
|
|
|
|
+ {
|
|
|
|
+ return CellCodeValue((int)cell.X, (int)cell.Y);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ static public MapSquare GetMapSquareAtCell(int tileX, int tileY)
|
|
|
|
+ {
|
|
|
|
+ if ((tileX >= 0) && (tileX < MapWidth) &&
|
|
|
|
+ (tileY >= 0) && (tileY < MapHeight))
|
|
|
|
+ {
|
|
|
|
+ return mapCells[tileX][tileY];
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public void SetMapSquareAtCell(
|
|
|
|
+ int tileX,
|
|
|
|
+ int tileY,
|
|
|
|
+ MapSquare tile)
|
|
|
|
+ {
|
|
|
|
+ if ((tileX >= 0) && (tileX < MapWidth) &&
|
|
|
|
+ (tileY >= 0) && (tileY < MapHeight))
|
|
|
|
+ {
|
|
|
|
+ mapCells[tileX][tileY] = tile;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public void SetTileAtCell(
|
|
|
|
+ int tileX,
|
|
|
|
+ int tileY,
|
|
|
|
+ int layer,
|
|
|
|
+ int tileIndex)
|
|
|
|
+ {
|
|
|
|
+ if ((tileX >= 0) && (tileX < MapWidth) &&
|
|
|
|
+ (tileY >= 0) && (tileY < MapHeight))
|
|
|
|
+ {
|
|
|
|
+ mapCells[tileX][tileY].LayerTiles[layer] = tileIndex;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public MapSquare GetMapSquareAtPixel(int pixelX, int pixelY)
|
|
|
|
+ {
|
|
|
|
+ return GetMapSquareAtCell(
|
|
|
|
+ GetCellByPixelX(pixelX),
|
|
|
|
+ GetCellByPixelY(pixelY));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static public MapSquare GetMapSquareAtPixel(Vector2 pixelLocation)
|
|
|
|
+ {
|
|
|
|
+ return GetMapSquareAtPixel(
|
|
|
|
+ (int)pixelLocation.X,
|
|
|
|
+ (int)pixelLocation.Y);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ public static void SaveMap(FileStream fileStream)
|
|
|
|
+ {
|
|
|
|
+ // Assumes mapCells is now a jagged array: MapSquare[][]
|
|
|
|
+ var options = new System.Text.Json.JsonSerializerOptions { WriteIndented = true };
|
|
|
|
+ using (var writer = new StreamWriter(fileStream, leaveOpen: false))
|
|
|
|
+ {
|
|
|
|
+ string json = System.Text.Json.JsonSerializer.Serialize(mapCells, options);
|
|
|
|
+ writer.Write(json);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void LoadMap(FileStream fileStream)
|
|
|
|
+ {
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ using (var reader = new StreamReader(fileStream, leaveOpen: false))
|
|
|
|
+ {
|
|
|
|
+ string json = reader.ReadToEnd();
|
|
|
|
+ mapCells = System.Text.Json.JsonSerializer.Deserialize<MapSquare[][]>(json);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ catch
|
|
|
|
+ {
|
|
|
|
+ ClearMap();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void LoadMapFromStream(Stream stream)
|
|
|
|
+ {
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ using (var reader = new StreamReader(stream, leaveOpen: true))
|
|
|
|
+ {
|
|
|
|
+ string json = reader.ReadToEnd();
|
|
|
|
+ mapCells = System.Text.Json.JsonSerializer.Deserialize<MapSquare[][]>(json);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ catch
|
|
|
|
+ {
|
|
|
|
+ ClearMap();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void ClearMap()
|
|
|
|
+ {
|
|
|
|
+ for (int x = 0; x < MapWidth; x++)
|
|
|
|
+ for (int y = 0; y < MapHeight; y++)
|
|
|
|
+ for (int z = 0; z < MapLayers; z++)
|
|
|
|
+ {
|
|
|
|
+ mapCells[x][y] = new MapSquare(2, 0, 0, "", true);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ static public void Draw(SpriteBatch spriteBatch)
|
|
|
|
+ {
|
|
|
|
+ int startX = GetCellByPixelX((int)Camera.Position.X);
|
|
|
|
+ int endX = GetCellByPixelX((int)Camera.Position.X +
|
|
|
|
+ Camera.ViewPortWidth);
|
|
|
|
+
|
|
|
|
+ int startY = GetCellByPixelY((int)Camera.Position.Y);
|
|
|
|
+ int endY = GetCellByPixelY((int)Camera.Position.Y +
|
|
|
|
+ Camera.ViewPortHeight);
|
|
|
|
+
|
|
|
|
+ for (int x = startX; x <= endX; x++)
|
|
|
|
+ for (int y = startY; y <= endY; y++)
|
|
|
|
+ {
|
|
|
|
+ for (int z = 0; z < MapLayers; z++)
|
|
|
|
+ {
|
|
|
|
+ if ((x >= 0) && (y >= 0) &&
|
|
|
|
+ (x < MapWidth) && (y < MapHeight))
|
|
|
|
+ {
|
|
|
|
+ spriteBatch.Draw(
|
|
|
|
+ tileSheet,
|
|
|
|
+ CellScreenRectangle(x, y),
|
|
|
|
+ TileSourceRectangle(mapCells[x][y].LayerTiles[z]),
|
|
|
|
+ Color.White,
|
|
|
|
+ 0.0f,
|
|
|
|
+ Vector2.Zero,
|
|
|
|
+ SpriteEffects.None,
|
|
|
|
+ 1f - ((float)z * 0.1f));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (EditorMode)
|
|
|
|
+ {
|
|
|
|
+ DrawEditModeItems(spriteBatch, x, y);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void DrawEditModeItems(
|
|
|
|
+ SpriteBatch spriteBatch,
|
|
|
|
+ int x,
|
|
|
|
+ int y)
|
|
|
|
+ {
|
|
|
|
+ if ((x < 0) || (x >= MapWidth) ||
|
|
|
|
+ (y < 0) || (y >= MapHeight))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (!CellIsPassable(x, y))
|
|
|
|
+ {
|
|
|
|
+ spriteBatch.Draw(
|
|
|
|
+ tileSheet,
|
|
|
|
+ CellScreenRectangle(x, y),
|
|
|
|
+ TileSourceRectangle(1),
|
|
|
|
+ new Color(255, 0, 0, 80),
|
|
|
|
+ 0.0f,
|
|
|
|
+ Vector2.Zero,
|
|
|
|
+ SpriteEffects.None,
|
|
|
|
+ 0.0f);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (mapCells[x][y].CodeValue != "")
|
|
|
|
+ {
|
|
|
|
+ Rectangle screenRect = CellScreenRectangle(x, y);
|
|
|
|
+
|
|
|
|
+ spriteBatch.DrawString(
|
|
|
|
+ spriteFont,
|
|
|
|
+ mapCells[x][y].CodeValue,
|
|
|
|
+ new Vector2(screenRect.X, screenRect.Y),
|
|
|
|
+ Color.White,
|
|
|
|
+ 0.0f,
|
|
|
|
+ Vector2.Zero,
|
|
|
|
+ 1.0f,
|
|
|
|
+ SpriteEffects.None,
|
|
|
|
+ 0.0f);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Helper to create a jagged array
|
|
|
|
+ private static MapSquare[][] CreateJaggedArray(int width, int height)
|
|
|
|
+ {
|
|
|
|
+ var arr = new MapSquare[width][];
|
|
|
|
+ for (int i = 0; i < width; i++)
|
|
|
|
+ arr[i] = new MapSquare[height];
|
|
|
|
+ return arr;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|