2
0

Camera2D.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. using System;
  2. using FarseerPhysics.Dynamics;
  3. using Microsoft.Xna.Framework;
  4. using Microsoft.Xna.Framework.Graphics;
  5. namespace FarseerPhysics.SamplesFramework
  6. {
  7. public class Camera2D
  8. {
  9. private const float _minZoom = 0.02f;
  10. private const float _maxZoom = 20f;
  11. private static GraphicsDevice _graphics;
  12. private Matrix _batchView;
  13. private Vector2 _currentPosition;
  14. private float _currentRotation;
  15. private float _currentZoom;
  16. private Vector2 _maxPosition;
  17. private float _maxRotation;
  18. private Vector2 _minPosition;
  19. private float _minRotation;
  20. private bool _positionTracking;
  21. private Matrix _projection;
  22. private bool _rotationTracking;
  23. private Vector2 _targetPosition;
  24. private float _targetRotation;
  25. private Body _trackingBody;
  26. private Vector2 _translateCenter;
  27. private Matrix _view;
  28. /// <summary>
  29. /// The constructor for the Camera2D class.
  30. /// </summary>
  31. /// <param name="graphics"></param>
  32. public Camera2D(GraphicsDevice graphics)
  33. {
  34. _graphics = graphics;
  35. _projection = Matrix.CreateOrthographicOffCenter(0f, ConvertUnits.ToSimUnits(_graphics.Viewport.Width),
  36. ConvertUnits.ToSimUnits(_graphics.Viewport.Height), 0f, 0f,
  37. 1f);
  38. _view = Matrix.Identity;
  39. _batchView = Matrix.Identity;
  40. _translateCenter = new Vector2(ConvertUnits.ToSimUnits(_graphics.Viewport.Width / 2f),
  41. ConvertUnits.ToSimUnits(_graphics.Viewport.Height / 2f));
  42. ResetCamera();
  43. }
  44. public Matrix View
  45. {
  46. get { return _batchView; }
  47. }
  48. public Matrix SimView
  49. {
  50. get { return _view; }
  51. }
  52. public Matrix SimProjection
  53. {
  54. get { return _projection; }
  55. }
  56. /// <summary>
  57. /// The current position of the camera.
  58. /// </summary>
  59. public Vector2 Position
  60. {
  61. get { return ConvertUnits.ToDisplayUnits(_currentPosition); }
  62. set
  63. {
  64. _targetPosition = ConvertUnits.ToSimUnits(value);
  65. if (_minPosition != _maxPosition)
  66. {
  67. Vector2.Clamp(ref _targetPosition, ref _minPosition, ref _maxPosition, out _targetPosition);
  68. }
  69. }
  70. }
  71. /// <summary>
  72. /// The furthest up, and the furthest left the camera can go.
  73. /// if this value equals maxPosition, then no clamping will be
  74. /// applied (unless you override that function).
  75. /// </summary>
  76. public Vector2 MinPosition
  77. {
  78. get { return ConvertUnits.ToDisplayUnits(_minPosition); }
  79. set { _minPosition = ConvertUnits.ToSimUnits(value); }
  80. }
  81. /// <summary>
  82. /// the furthest down, and the furthest right the camera will go.
  83. /// if this value equals minPosition, then no clamping will be
  84. /// applied (unless you override that function).
  85. /// </summary>
  86. public Vector2 MaxPosition
  87. {
  88. get { return ConvertUnits.ToDisplayUnits(_maxPosition); }
  89. set { _maxPosition = ConvertUnits.ToSimUnits(value); }
  90. }
  91. /// <summary>
  92. /// The current rotation of the camera in radians.
  93. /// </summary>
  94. public float Rotation
  95. {
  96. get { return _currentRotation; }
  97. set
  98. {
  99. _targetRotation = value % MathHelper.TwoPi;
  100. if (_minRotation != _maxRotation)
  101. {
  102. _targetRotation = MathHelper.Clamp(_targetRotation, _minRotation, _maxRotation);
  103. }
  104. }
  105. }
  106. /// <summary>
  107. /// Gets or sets the minimum rotation in radians.
  108. /// </summary>
  109. /// <value>The min rotation.</value>
  110. public float MinRotation
  111. {
  112. get { return _minRotation; }
  113. set { _minRotation = MathHelper.Clamp(value, -MathHelper.Pi, 0f); }
  114. }
  115. /// <summary>
  116. /// Gets or sets the maximum rotation in radians.
  117. /// </summary>
  118. /// <value>The max rotation.</value>
  119. public float MaxRotation
  120. {
  121. get { return _maxRotation; }
  122. set { _maxRotation = MathHelper.Clamp(value, 0f, MathHelper.Pi); }
  123. }
  124. /// <summary>
  125. /// The current rotation of the camera in radians.
  126. /// </summary>
  127. public float Zoom
  128. {
  129. get { return _currentZoom; }
  130. set
  131. {
  132. _currentZoom = value;
  133. _currentZoom = MathHelper.Clamp(_currentZoom, _minZoom, _maxZoom);
  134. }
  135. }
  136. /// <summary>
  137. /// the body that this camera is currently tracking.
  138. /// Null if not tracking any.
  139. /// </summary>
  140. public Body TrackingBody
  141. {
  142. get { return _trackingBody; }
  143. set
  144. {
  145. _trackingBody = value;
  146. if (_trackingBody != null)
  147. {
  148. _positionTracking = true;
  149. }
  150. }
  151. }
  152. public bool EnablePositionTracking
  153. {
  154. get { return _positionTracking; }
  155. set
  156. {
  157. if (value && _trackingBody != null)
  158. {
  159. _positionTracking = true;
  160. }
  161. else
  162. {
  163. _positionTracking = false;
  164. }
  165. }
  166. }
  167. public bool EnableRotationTracking
  168. {
  169. get { return _rotationTracking; }
  170. set
  171. {
  172. if (value && _trackingBody != null)
  173. {
  174. _rotationTracking = true;
  175. }
  176. else
  177. {
  178. _rotationTracking = false;
  179. }
  180. }
  181. }
  182. public bool EnableTracking
  183. {
  184. set
  185. {
  186. EnablePositionTracking = value;
  187. EnableRotationTracking = value;
  188. }
  189. }
  190. public void MoveCamera(Vector2 amount)
  191. {
  192. _currentPosition += amount;
  193. if (_minPosition != _maxPosition)
  194. {
  195. Vector2.Clamp(ref _currentPosition, ref _minPosition, ref _maxPosition, out _currentPosition);
  196. }
  197. _targetPosition = _currentPosition;
  198. _positionTracking = false;
  199. _rotationTracking = false;
  200. }
  201. public void RotateCamera(float amount)
  202. {
  203. _currentRotation += amount;
  204. if (_minRotation != _maxRotation)
  205. {
  206. _currentRotation = MathHelper.Clamp(_currentRotation, _minRotation, _maxRotation);
  207. }
  208. _targetRotation = _currentRotation;
  209. _positionTracking = false;
  210. _rotationTracking = false;
  211. }
  212. /// <summary>
  213. /// Resets the camera to default values.
  214. /// </summary>
  215. public void ResetCamera()
  216. {
  217. _currentPosition = Vector2.Zero;
  218. _targetPosition = Vector2.Zero;
  219. _minPosition = Vector2.Zero;
  220. _maxPosition = Vector2.Zero;
  221. _currentRotation = 0f;
  222. _targetRotation = 0f;
  223. _minRotation = -MathHelper.Pi;
  224. _maxRotation = MathHelper.Pi;
  225. _positionTracking = false;
  226. _rotationTracking = false;
  227. _currentZoom = 1f;
  228. SetView();
  229. }
  230. public void Jump2Target()
  231. {
  232. _currentPosition = _targetPosition;
  233. _currentRotation = _targetRotation;
  234. SetView();
  235. }
  236. private void SetView()
  237. {
  238. Matrix matRotation = Matrix.CreateRotationZ(_currentRotation);
  239. Matrix matZoom = Matrix.CreateScale(_currentZoom);
  240. Vector3 translateCenter = new Vector3(_translateCenter, 0f);
  241. Vector3 translateBody = new Vector3(-_currentPosition, 0f);
  242. _view = Matrix.CreateTranslation(translateBody) *
  243. matRotation *
  244. matZoom *
  245. Matrix.CreateTranslation(translateCenter);
  246. translateCenter = ConvertUnits.ToDisplayUnits(translateCenter);
  247. translateBody = ConvertUnits.ToDisplayUnits(translateBody);
  248. _batchView = Matrix.CreateTranslation(translateBody) *
  249. matRotation *
  250. matZoom *
  251. Matrix.CreateTranslation(translateCenter);
  252. }
  253. /// <summary>
  254. /// Moves the camera forward one timestep.
  255. /// </summary>
  256. public void Update(GameTime gameTime)
  257. {
  258. if (_trackingBody != null)
  259. {
  260. if (_positionTracking)
  261. {
  262. _targetPosition = _trackingBody.Position;
  263. if (_minPosition != _maxPosition)
  264. {
  265. Vector2.Clamp(ref _targetPosition, ref _minPosition, ref _maxPosition, out _targetPosition);
  266. }
  267. }
  268. if (_rotationTracking)
  269. {
  270. _targetRotation = -_trackingBody.Rotation % MathHelper.TwoPi;
  271. if (_minRotation != _maxRotation)
  272. {
  273. _targetRotation = MathHelper.Clamp(_targetRotation, _minRotation, _maxRotation);
  274. }
  275. }
  276. }
  277. Vector2 delta = _targetPosition - _currentPosition;
  278. float distance = delta.Length();
  279. if (distance > 0f)
  280. {
  281. delta /= distance;
  282. }
  283. float inertia;
  284. if (distance < 10f)
  285. {
  286. inertia = (float) Math.Pow(distance / 10.0, 2.0);
  287. }
  288. else
  289. {
  290. inertia = 1f;
  291. }
  292. float rotDelta = _targetRotation - _currentRotation;
  293. float rotInertia;
  294. if (Math.Abs(rotDelta) < 5f)
  295. {
  296. rotInertia = (float) Math.Pow(rotDelta / 5.0, 2.0);
  297. }
  298. else
  299. {
  300. rotInertia = 1f;
  301. }
  302. if (Math.Abs(rotDelta) > 0f)
  303. {
  304. rotDelta /= Math.Abs(rotDelta);
  305. }
  306. _currentPosition += 100f * delta * inertia * (float) gameTime.ElapsedGameTime.TotalSeconds;
  307. _currentRotation += 80f * rotDelta * rotInertia * (float) gameTime.ElapsedGameTime.TotalSeconds;
  308. SetView();
  309. }
  310. public Vector2 ConvertScreenToWorld(Vector2 location)
  311. {
  312. Vector3 t = new Vector3(location, 0);
  313. t = _graphics.Viewport.Unproject(t, _projection, _view, Matrix.Identity);
  314. return new Vector2(t.X, t.Y);
  315. }
  316. public Vector2 ConvertWorldToScreen(Vector2 location)
  317. {
  318. Vector3 t = new Vector3(location, 0);
  319. t = _graphics.Viewport.Project(t, _projection, _view, Matrix.Identity);
  320. return new Vector2(t.X, t.Y);
  321. }
  322. }
  323. }