OrthographicCamera.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. using System;
  2. using Microsoft.Xna.Framework;
  3. using Microsoft.Xna.Framework.Graphics;
  4. using MonoGame.Extended.ViewportAdapters;
  5. namespace MonoGame.Extended
  6. {
  7. public sealed class OrthographicCamera : Camera<Vector2>, IMovable, IRotatable
  8. {
  9. private readonly ViewportAdapter _viewportAdapter;
  10. private float _maximumZoom = float.MaxValue;
  11. private float _minimumZoom;
  12. private float _zoom;
  13. private float _pitch;
  14. private float _maximumPitch = float.MaxValue;
  15. private float _minimumPitch;
  16. public OrthographicCamera(GraphicsDevice graphicsDevice)
  17. : this(new DefaultViewportAdapter(graphicsDevice))
  18. {
  19. }
  20. public OrthographicCamera(ViewportAdapter viewportAdapter)
  21. {
  22. _viewportAdapter = viewportAdapter;
  23. Rotation = 0;
  24. Zoom = 1;
  25. Pitch = 1;
  26. Origin = new Vector2(viewportAdapter.VirtualWidth/2f, viewportAdapter.VirtualHeight/2f);
  27. Position = Vector2.Zero;
  28. }
  29. public override Vector2 Position { get; set; }
  30. public override float Rotation { get; set; }
  31. public override Vector2 Origin { get; set; }
  32. public override Vector2 Center => Position + Origin;
  33. public override float Zoom
  34. {
  35. get => _zoom;
  36. set
  37. {
  38. if ((value < MinimumZoom) || (value > MaximumZoom))
  39. throw new ArgumentException("Zoom must be between MinimumZoom and MaximumZoom");
  40. _zoom = value;
  41. }
  42. }
  43. public override float MinimumZoom
  44. {
  45. get => _minimumZoom;
  46. set
  47. {
  48. if (value < 0)
  49. throw new ArgumentException("MinimumZoom must be greater than zero");
  50. if (Zoom < value)
  51. Zoom = MinimumZoom;
  52. _minimumZoom = value;
  53. }
  54. }
  55. public override float MaximumZoom
  56. {
  57. get => _maximumZoom;
  58. set
  59. {
  60. if (value < 0)
  61. throw new ArgumentException("MaximumZoom must be greater than zero");
  62. if (Zoom > value)
  63. Zoom = value;
  64. _maximumZoom = value;
  65. }
  66. }
  67. public override float Pitch
  68. {
  69. get => _pitch;
  70. set
  71. {
  72. if ((value < MinimumPitch) || (value > MaximumPitch))
  73. throw new ArgumentException("Pitch must be between MinimumPitch and MaximumPitch");
  74. _pitch = value;
  75. }
  76. }
  77. public override float MinimumPitch
  78. {
  79. get => _minimumPitch;
  80. set
  81. {
  82. if (value < 0)
  83. throw new ArgumentException("MinimumPitch must be greater than zero");
  84. if (Pitch < value)
  85. Pitch = MinimumPitch;
  86. _minimumPitch = value;
  87. }
  88. }
  89. public override float MaximumPitch
  90. {
  91. get => _maximumPitch;
  92. set
  93. {
  94. if (value < 0)
  95. throw new ArgumentException("MaximumPitch must be greater than zero");
  96. if (Pitch > value)
  97. Pitch = value;
  98. _maximumPitch = value;
  99. }
  100. }
  101. public override RectangleF BoundingRectangle
  102. {
  103. get
  104. {
  105. var frustum = GetBoundingFrustum();
  106. var corners = frustum.GetCorners();
  107. var topLeft = corners[0];
  108. var bottomRight = corners[2];
  109. var width = bottomRight.X - topLeft.X;
  110. var height = bottomRight.Y - topLeft.Y;
  111. return new RectangleF(topLeft.X, topLeft.Y, width, height);
  112. }
  113. }
  114. public override void Move(Vector2 direction)
  115. {
  116. Position += Vector2.Transform(direction, Matrix.CreateRotationZ(-Rotation));
  117. }
  118. public override void Rotate(float deltaRadians)
  119. {
  120. Rotation += deltaRadians;
  121. }
  122. public override void ZoomIn(float deltaZoom)
  123. {
  124. ClampZoom(Zoom + deltaZoom);
  125. }
  126. public override void ZoomOut(float deltaZoom)
  127. {
  128. ClampZoom(Zoom - deltaZoom);
  129. }
  130. private void ClampZoom(float value)
  131. {
  132. if (value < MinimumZoom)
  133. Zoom = MinimumZoom;
  134. else
  135. Zoom = value > MaximumZoom ? MaximumZoom : value;
  136. }
  137. public override void PitchUp(float deltaPitch)
  138. {
  139. ClampPitch(Pitch + deltaPitch);
  140. }
  141. public override void PitchDown(float deltaPitch)
  142. {
  143. ClampPitch(Pitch - deltaPitch);
  144. }
  145. private void ClampPitch(float value)
  146. {
  147. if (value < MinimumPitch)
  148. Pitch = MinimumPitch;
  149. else
  150. Pitch = value > MaximumPitch ? MaximumPitch : value;
  151. }
  152. public override void LookAt(Vector2 position)
  153. {
  154. Position = position - new Vector2(_viewportAdapter.VirtualWidth/2f, _viewportAdapter.VirtualHeight/2f);
  155. }
  156. public Vector2 WorldToScreen(float x, float y)
  157. {
  158. return WorldToScreen(new Vector2(x, y));
  159. }
  160. public override Vector2 WorldToScreen(Vector2 worldPosition)
  161. {
  162. var viewport = _viewportAdapter.Viewport;
  163. return Vector2.Transform(worldPosition + new Vector2(viewport.X, viewport.Y), GetViewMatrix());
  164. }
  165. public Vector2 ScreenToWorld(float x, float y)
  166. {
  167. return ScreenToWorld(new Vector2(x, y));
  168. }
  169. public override Vector2 ScreenToWorld(Vector2 screenPosition)
  170. {
  171. var viewport = _viewportAdapter.Viewport;
  172. return Vector2.Transform(screenPosition - new Vector2(viewport.X, viewport.Y),
  173. Matrix.Invert(GetViewMatrix()));
  174. }
  175. public Matrix GetViewMatrix(Vector2 parallaxFactor)
  176. {
  177. return GetVirtualViewMatrix(parallaxFactor)*_viewportAdapter.GetScaleMatrix();
  178. }
  179. private Matrix GetVirtualViewMatrix(Vector2 parallaxFactor)
  180. {
  181. return
  182. Matrix.CreateTranslation(new Vector3(-Position*parallaxFactor, 0.0f))*
  183. Matrix.CreateTranslation(new Vector3(-Origin, 0.0f))*
  184. Matrix.CreateRotationZ(Rotation)*
  185. Matrix.CreateScale(Zoom, Zoom * Pitch, 1)*
  186. Matrix.CreateTranslation(new Vector3(Origin, 0.0f));
  187. }
  188. private Matrix GetVirtualViewMatrix()
  189. {
  190. return GetVirtualViewMatrix(Vector2.One);
  191. }
  192. public override Matrix GetViewMatrix()
  193. {
  194. return GetViewMatrix(Vector2.One);
  195. }
  196. public override Matrix GetInverseViewMatrix()
  197. {
  198. return Matrix.Invert(GetViewMatrix());
  199. }
  200. private Matrix GetProjectionMatrix(Matrix viewMatrix)
  201. {
  202. var projection = Matrix.CreateOrthographicOffCenter(0, _viewportAdapter.VirtualWidth, _viewportAdapter.VirtualHeight, 0, -1, 0);
  203. Matrix.Multiply(ref viewMatrix, ref projection, out projection);
  204. return projection;
  205. }
  206. public override BoundingFrustum GetBoundingFrustum()
  207. {
  208. var viewMatrix = GetVirtualViewMatrix();
  209. var projectionMatrix = GetProjectionMatrix(viewMatrix);
  210. return new BoundingFrustum(projectionMatrix);
  211. }
  212. public ContainmentType Contains(Point point)
  213. {
  214. return Contains(point.ToVector2());
  215. }
  216. public override ContainmentType Contains(Vector2 vector2)
  217. {
  218. return GetBoundingFrustum().Contains(new Vector3(vector2.X, vector2.Y, 0));
  219. }
  220. public override ContainmentType Contains(Rectangle rectangle)
  221. {
  222. var max = new Vector3(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height, 0.5f);
  223. var min = new Vector3(rectangle.X, rectangle.Y, 0.5f);
  224. var boundingBox = new BoundingBox(min, max);
  225. return GetBoundingFrustum().Contains(boundingBox);
  226. }
  227. }
  228. }