Sprite.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright (c) Craftwork Games. All rights reserved.
  2. // Licensed under the MIT license.
  3. // See LICENSE file in the project root for full license information.
  4. using System;
  5. using System.Linq;
  6. using Microsoft.Xna.Framework;
  7. using Microsoft.Xna.Framework.Graphics;
  8. namespace MonoGame.Extended.Graphics;
  9. /// <summary>
  10. /// Represents a drawable 2D texture region with additional properties for rendering, such as position, scale,
  11. /// rotation, and color.
  12. /// </summary>
  13. public class Sprite : IColorable
  14. {
  15. private Texture2DRegion _textureRegion;
  16. /// <summary>
  17. /// Gets or sets a value indicating whether this sprite is visible.
  18. /// </summary>
  19. public bool IsVisible { get; set; }
  20. /// <summary>
  21. /// Gets or sets the color mask used when rendering this sprite.
  22. /// </summary>
  23. /// <remarks>
  24. /// The color mask is applied to the sprite's texture by multiplying each pixel's color value with the specified
  25. /// color. For example, setting the color to `Color.Red` will make the sprite appear as a red tint over its
  26. /// texture.
  27. /// </remarks>
  28. public Color Color { get; set; }
  29. /// <summary>
  30. /// Gets or sets the alpha transparency value used when rendering this sprite.
  31. /// </summary>
  32. /// <remarks>
  33. /// The alpha value should be between 0 (fully transparent) and 1 (fully opaque).
  34. /// </remarks>
  35. public float Alpha { get; set; }
  36. /// <summary>
  37. /// Gets or sets the layer depth used when rendering this sprite.
  38. /// </summary>
  39. /// <remarks>
  40. /// Sprites with higher depth values are rendered on top of those with lower depth values.
  41. /// </remarks>
  42. public float Depth { get; set; }
  43. /// <summary>
  44. /// Gets or sets the sprite effects to apply when rendering this sprite.
  45. /// </summary>
  46. /// <remarks>
  47. /// This specifies the desired horizontal and/or vertical flip effect of the sprite.
  48. /// </remarks>
  49. public SpriteEffects Effect { get; set; }
  50. /// <summary>
  51. /// Gets or Sets an object that contains user defined data about this sprite.
  52. /// </summary>
  53. public object Tag { get; set; }
  54. /// <summary>
  55. /// Gets the size of the sprite.
  56. /// </summary>
  57. public Point Size => TextureRegion.OriginalSize;
  58. /// <summary>
  59. /// Gets or sets the origin of this sprite.
  60. /// </summary>
  61. /// <remarks>
  62. /// The origin is relative to the bounds of the texture region and represents the point around which the sprite is
  63. /// rotated and scaled.
  64. /// </remarks>
  65. public Vector2 Origin { get; set; }
  66. /// <summary>
  67. /// Gets or sets the normalized origin of this sprite relative to its texture region.
  68. /// </summary>
  69. /// <remarks>
  70. /// The normalized origin represents the origin as a fraction of the texture region's UV coordinates,
  71. /// where (0, 0) is the top-left corner and (1, 1) is the bottom-right corner.
  72. /// </remarks>
  73. public Vector2 OriginNormalized
  74. {
  75. get { return new Vector2(Origin.X / TextureRegion.OriginalSize.Width, Origin.Y / TextureRegion.OriginalSize.Height); }
  76. set { Origin = new Vector2(value.X * TextureRegion.OriginalSize.Width, value.Y * TextureRegion.OriginalSize.Height); }
  77. }
  78. /// <summary>
  79. /// Gets or sets the source texture region of this sprite.
  80. /// </summary>
  81. /// <exception cref="ArgumentNullException">Thrown when setting to a null texture region.</exception>
  82. /// <exception cref="ObjectDisposedException">
  83. /// Thrown if the source texture of the assigned <see cref="Texture2DRegion"/> has been disposed of when setting.
  84. /// </exception>
  85. public Texture2DRegion TextureRegion
  86. {
  87. get => _textureRegion;
  88. set
  89. {
  90. ArgumentNullException.ThrowIfNull(value);
  91. if (value.Texture.IsDisposed)
  92. {
  93. throw new ObjectDisposedException(nameof(value), $"The source {nameof(Texture2D)} of the {nameof(TextureRegion)} was disposed prior to setting this property.");
  94. }
  95. _textureRegion = value;
  96. if (value.OriginNormalized.HasValue)
  97. {
  98. OriginNormalized = value.OriginNormalized.Value;
  99. }
  100. }
  101. }
  102. /// <summary>
  103. /// Initializes a new instance of the <see cref="Sprite"/> class with the specified texture.
  104. /// </summary>
  105. /// <param name="texture">The source texture of the sprite.</param>
  106. /// <exception cref="ArgumentNullException">
  107. /// Thrown if the <paramref name="texture"/> parameter is <see langword="null"/>.
  108. /// </exception>
  109. /// <exception cref="ObjectDisposedException">
  110. /// Thrown if the <paramref name="texture"/> parameter was disposed of prior.
  111. /// </exception>
  112. public Sprite(Texture2D texture)
  113. : this(new Texture2DRegion(texture))
  114. {
  115. }
  116. /// <summary>
  117. /// Initializes a new instance of the <see cref="Sprite"/> class with the specified texture region.
  118. /// The sprite represents a renderable 2D image defined by the given texture region.
  119. /// </summary>
  120. /// <param name="textureRegion">The source texture region of the sprite.</param>
  121. /// <exception cref="ArgumentNullException">
  122. /// Thrown if the <paramref name="textureRegion"/> parameter is <see langword="null"/>.
  123. /// </exception>
  124. /// <exception cref="ObjectDisposedException">
  125. /// Thrown if the source texture of the <paramref name="textureRegion"/> parameter has been disposed of.
  126. /// </exception>
  127. public Sprite(Texture2DRegion textureRegion)
  128. {
  129. ArgumentNullException.ThrowIfNull(textureRegion);
  130. if (textureRegion.Texture.IsDisposed)
  131. {
  132. throw new ObjectDisposedException(nameof(textureRegion), $"The source {nameof(Texture2D)} of the {nameof(textureRegion)} was disposed prior.");
  133. }
  134. _textureRegion = textureRegion;
  135. Alpha = 1.0f;
  136. Color = Color.White;
  137. IsVisible = true;
  138. Effect = SpriteEffects.None;
  139. OriginNormalized = textureRegion.OriginNormalized ?? Vector2.Zero;
  140. Depth = 0.0f;
  141. }
  142. /// <summary>
  143. /// Gets the bounding rectangle of the sprite in world/screen coordinates.
  144. /// </summary>
  145. /// <param name="transform">The transformation of the sprite.</param>
  146. /// <returns>The bounding rectangle of the sprite in world/screen coordinates.</returns>
  147. public RectangleF GetBoundingRectangle(Transform2 transform)
  148. {
  149. return GetBoundingRectangle(transform.Position, transform.Rotation, transform.Scale);
  150. }
  151. /// <summary>
  152. /// Gets the bounding rectangle of the sprite in world/screen coordinates.
  153. /// </summary>
  154. /// <param name="position">The xy-coordinate position of the sprite in world/screen coordinates.</param>
  155. /// <param name="rotation">The rotation, in radians, of the sprite.</param>
  156. /// <param name="scale">The scale of the sprite.</param>
  157. /// <returns>The bounding rectangle of the sprite in world/screen coordinates.</returns>
  158. public RectangleF GetBoundingRectangle(Vector2 position, float rotation, Vector2 scale)
  159. {
  160. var corners = GetCorners(position, rotation, scale);
  161. var min = new Vector2(corners.Min(i => i.X), corners.Min(i => i.Y));
  162. var max = new Vector2(corners.Max(i => i.X), corners.Max(i => i.Y));
  163. return new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y);
  164. }
  165. /// <summary>
  166. /// Gets the corner points of the sprite in world/screen coordinates.
  167. /// </summary>
  168. /// <param name="position">The xy-coordinate position of the sprite in world/screen coordinates.</param>
  169. /// <param name="rotation">The rotation, in radians, of the sprite.</param>
  170. /// <param name="scale">The scale of the sprite.</param>
  171. /// <returns>The corner points of the sprite in world/screen coordinates.</returns>
  172. public Vector2[] GetCorners(Vector2 position, float rotation, Vector2 scale)
  173. {
  174. var min = -Origin;
  175. var max = min + new Vector2(TextureRegion.OriginalSize.Width, TextureRegion.OriginalSize.Height);
  176. var offset = position;
  177. if (scale != Vector2.One)
  178. {
  179. min *= scale;
  180. max = max * scale;
  181. }
  182. var corners = new Vector2[4];
  183. corners[0] = min;
  184. corners[1] = new Vector2(max.X, min.Y);
  185. corners[2] = max;
  186. corners[3] = new Vector2(min.X, max.Y);
  187. if (rotation != 0)
  188. {
  189. var matrix = Matrix.CreateRotationZ(rotation);
  190. for (var i = 0; i < 4; i++)
  191. {
  192. corners[i] = Vector2.Transform(corners[i], matrix);
  193. }
  194. }
  195. for (var i = 0; i < 4; i++)
  196. {
  197. corners[i] += offset;
  198. }
  199. return corners;
  200. }
  201. }