TileGrid.cs 9.8 KB

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