TileGrid.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. //-----------------------------------------------------------------------------
  2. // TileGrid.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using Microsoft.Xna.Framework;
  10. using Microsoft.Xna.Framework.Audio;
  11. using Microsoft.Xna.Framework.Graphics;
  12. using Microsoft.Xna.Framework.Input;
  13. using Microsoft.Xna.Framework.Content;
  14. using Microsoft.Xna.Framework.Media;
  15. namespace TiledSprites
  16. {
  17. /// <summary>
  18. /// EDUCATIONAL: Class used to align tiles to a regular grid.
  19. /// This represents a tiling "layer" in this sample
  20. /// </summary>
  21. public class TileGrid
  22. {
  23. private int[][] grid;
  24. private GraphicsDeviceManager graphics;
  25. private SpriteSheet sheet;
  26. private int width;
  27. private int height;
  28. private int cellWidth;
  29. private int cellHeight;
  30. private Vector2 worldOffset;
  31. private bool visibilityChanged;
  32. private Rectangle visibleTiles;
  33. //drawing parameters
  34. private Vector2 cameraPostionValue;
  35. private float zoomValue;
  36. private Vector2 scaleValue;
  37. private float rotationValue;
  38. private Matrix rotationMatrix;
  39. private Vector2 displaySize;
  40. private Color layerColor = Color.White;
  41. public TileGrid(int tileWidth, int tileHeight, int numXTiles, int numYTiles,
  42. Vector2 offset, SpriteSheet tileSheet,
  43. GraphicsDeviceManager graphicsComponent)
  44. {
  45. if (graphicsComponent == null)
  46. {
  47. throw new ArgumentNullException("graphicsComponent");
  48. }
  49. graphics = graphicsComponent;
  50. sheet = tileSheet;
  51. width = numXTiles;
  52. height = numYTiles;
  53. cellWidth = tileWidth;
  54. cellHeight = tileHeight;
  55. worldOffset = offset;
  56. visibleTiles = new Rectangle(0, 0, width, height);
  57. grid = new int[width][];
  58. for (int i = 0; i < width; i++)
  59. {
  60. grid[i] = new int[height];
  61. for (int j = 0; j < height; j++)
  62. {
  63. grid[i][j] = 0;
  64. }
  65. }
  66. scaleValue = Vector2.One;
  67. zoomValue = 1.0f;
  68. CameraPosition = Vector2.Zero;
  69. displaySize.X = graphics.GraphicsDevice.PresentationParameters.BackBufferWidth;
  70. displaySize.Y = graphics.GraphicsDevice.PresentationParameters.BackBufferHeight;
  71. graphicsComponent.DeviceReset += delegate (object sender, EventArgs e)
  72. {
  73. displaySize.X = graphics.GraphicsDevice.PresentationParameters.BackBufferWidth;
  74. displaySize.Y = graphics.GraphicsDevice.PresentationParameters.BackBufferHeight;
  75. visibilityChanged = true;
  76. };
  77. }
  78. public Vector2 CameraPosition
  79. {
  80. set
  81. {
  82. cameraPostionValue = value;
  83. visibilityChanged = true;
  84. }
  85. get
  86. {
  87. return cameraPostionValue;
  88. }
  89. }
  90. public float CameraRotation
  91. {
  92. set
  93. {
  94. rotationValue = value;
  95. rotationMatrix = Matrix.CreateRotationZ(rotationValue);
  96. visibilityChanged = true;
  97. }
  98. get
  99. {
  100. return rotationValue;
  101. }
  102. }
  103. public float CameraZoom
  104. {
  105. set
  106. {
  107. zoomValue = value;
  108. visibilityChanged = true;
  109. }
  110. get
  111. {
  112. return zoomValue;
  113. }
  114. }
  115. public Color Color
  116. {
  117. set
  118. {
  119. layerColor = value;
  120. }
  121. get
  122. {
  123. return layerColor;
  124. }
  125. }
  126. public Vector2 TileScale
  127. {
  128. set
  129. {
  130. scaleValue = value;
  131. visibilityChanged = true;
  132. }
  133. get
  134. {
  135. return scaleValue;
  136. }
  137. }
  138. public Vector2 Position
  139. {
  140. set
  141. {
  142. worldOffset = value;
  143. visibilityChanged = true;
  144. }
  145. get
  146. {
  147. return worldOffset;
  148. }
  149. }
  150. public void SetTile(int xIndex, int yIndex, int tile)
  151. {
  152. grid[xIndex][yIndex] = tile;
  153. }
  154. /// <summary>
  155. /// This function determines which tiles are visible on the screen,
  156. /// given the current camera position, rotation, zoom, and tile scale
  157. /// </summary>
  158. private void DetermineVisibility()
  159. {
  160. //create the view rectangle
  161. Vector2 upperLeft = Vector2.Zero;
  162. Vector2 upperRight = Vector2.Zero;
  163. Vector2 lowerLeft = Vector2.Zero;
  164. Vector2 lowerRight = Vector2.Zero;
  165. lowerRight.X = ((displaySize.X / 2) / zoomValue);
  166. lowerRight.Y = ((displaySize.Y / 2) / zoomValue);
  167. upperRight.X = lowerRight.X;
  168. upperRight.Y = -lowerRight.Y;
  169. lowerLeft.X = -lowerRight.X;
  170. lowerLeft.Y = lowerRight.Y;
  171. upperLeft.X = -lowerRight.X;
  172. upperLeft.Y = -lowerRight.Y;
  173. //rotate the view rectangle appropriately
  174. Vector2.Transform(ref upperLeft, ref rotationMatrix, out upperLeft);
  175. Vector2.Transform(ref lowerRight, ref rotationMatrix, out lowerRight);
  176. Vector2.Transform(ref upperRight, ref rotationMatrix, out upperRight);
  177. Vector2.Transform(ref lowerLeft, ref rotationMatrix, out lowerLeft);
  178. lowerLeft += (cameraPostionValue);
  179. lowerRight += (cameraPostionValue);
  180. upperRight += (cameraPostionValue);
  181. upperLeft += (cameraPostionValue);
  182. //the idea here is to figure out the smallest square
  183. //(in tile space) that contains tiles
  184. //the offset is calculated before scaling
  185. float top = MathHelper.Min(
  186. MathHelper.Min(upperLeft.Y, lowerRight.Y),
  187. MathHelper.Min(upperRight.Y, lowerLeft.Y)) -
  188. worldOffset.Y;
  189. float bottom = MathHelper.Max(
  190. MathHelper.Max(upperLeft.Y, lowerRight.Y),
  191. MathHelper.Max(upperRight.Y, lowerLeft.Y)) -
  192. worldOffset.Y;
  193. float right = MathHelper.Max(
  194. MathHelper.Max(upperLeft.X, lowerRight.X),
  195. MathHelper.Max(upperRight.X, lowerLeft.X)) -
  196. worldOffset.X;
  197. float left = MathHelper.Min(
  198. MathHelper.Min(upperLeft.X, lowerRight.X),
  199. MathHelper.Min(upperRight.X, lowerLeft.X)) -
  200. worldOffset.X;
  201. //now figure out where we are in the tile sheet
  202. float scaledTileWidth = (float)cellWidth * scaleValue.X;
  203. float scaledTileHeight = (float)cellHeight * scaleValue.Y;
  204. //get the visible tiles
  205. visibleTiles.X = (int)(left / (scaledTileWidth));
  206. visibleTiles.Y = (int)(top / (scaledTileWidth));
  207. //get the number of visible tiles
  208. visibleTiles.Height =
  209. (int)((bottom) / (scaledTileHeight)) - visibleTiles.Y + 1;
  210. visibleTiles.Width =
  211. (int)((right) / (scaledTileWidth)) - visibleTiles.X + 1;
  212. //clamp the "upper left" values to 0
  213. if (visibleTiles.X < 0)
  214. visibleTiles.X = 0;
  215. if (visibleTiles.X > (width - 1))
  216. visibleTiles.X = width;
  217. if (visibleTiles.Y < 0)
  218. visibleTiles.Y = 0;
  219. if (visibleTiles.Y > (height - 1))
  220. visibleTiles.Y = height;
  221. //clamp the "lower right" values to the gameboard size
  222. if (visibleTiles.Right > (width - 1))
  223. visibleTiles.Width = (width - visibleTiles.X);
  224. if (visibleTiles.Right < 0)
  225. visibleTiles.Width = 0;
  226. if (visibleTiles.Bottom > (height - 1))
  227. visibleTiles.Height = (height - visibleTiles.Y);
  228. if (visibleTiles.Bottom < 0)
  229. visibleTiles.Height = 0;
  230. visibilityChanged = false;
  231. }
  232. public void Draw(SpriteBatch batch)
  233. {
  234. if (visibilityChanged)
  235. DetermineVisibility();
  236. float scaledTileWidth = (float)cellWidth * scaleValue.X;
  237. float scaledTileHeight = (float)cellHeight * scaleValue.Y;
  238. Vector2 screenCenter = new Vector2((displaySize.X / 2), (displaySize.Y / 2));
  239. //begin a batch of sprites to be drawn all at once
  240. batch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
  241. Rectangle sourceRect = new Rectangle();
  242. Vector2 scale = Vector2.One;
  243. for (int x = visibleTiles.Left; x < visibleTiles.Right; x++)
  244. {
  245. for (int y = visibleTiles.Top; y < visibleTiles.Bottom; y++)
  246. {
  247. if (grid[x][y] != 0)
  248. {
  249. //Get the tile's position from the grid
  250. //in this section we're using reference methods
  251. //for the high frequency math functions
  252. Vector2 position = Vector2.Zero;
  253. position.X = (float)x * scaledTileWidth;
  254. position.Y = (float)y * scaledTileHeight;
  255. //offset the positions by the word position of the tile grid
  256. //this is the actual position of the tile in world coordinates
  257. Vector2.Add(ref position, ref worldOffset, out position);
  258. //Now, we get the camera position relative to the tile's position
  259. Vector2.Subtract(ref cameraPostionValue, ref position,
  260. out position);
  261. //get the tile's final size (note that scaling is done after
  262. //determining the position)
  263. Vector2.Multiply(ref scaleValue, zoomValue, out scale);
  264. //get the source rectnagle that defines the tile
  265. sheet.GetRectangle(ref grid[x][y], out sourceRect);
  266. //Draw the tile. Notice that position is used as the offset and
  267. //the screen center is used as a position. This is required to
  268. //enable scaling and rotation about the center of the screen by
  269. //drawing tiles as an offset from the center coordinate
  270. batch.Draw(sheet.Texture, screenCenter, sourceRect, layerColor,
  271. rotationValue, position, scale, SpriteEffects.None, 0.0f);
  272. }
  273. }
  274. }
  275. batch.End();
  276. }
  277. }
  278. }