ChaseCamera.java 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. /*
  2. * Copyright (c) 2009-2012 jMonkeyEngine
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  12. * * Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
  17. * may be used to endorse or promote products derived from this software
  18. * without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  22. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. package com.jme3.input;
  33. import com.jme3.export.InputCapsule;
  34. import com.jme3.export.JmeExporter;
  35. import com.jme3.export.JmeImporter;
  36. import com.jme3.export.OutputCapsule;
  37. import com.jme3.input.controls.*;
  38. import com.jme3.math.FastMath;
  39. import com.jme3.math.Vector3f;
  40. import com.jme3.renderer.Camera;
  41. import com.jme3.renderer.RenderManager;
  42. import com.jme3.renderer.ViewPort;
  43. import com.jme3.scene.Spatial;
  44. import com.jme3.scene.control.Control;
  45. import java.io.IOException;
  46. /**
  47. * A camera that follows a spatial and can turn around it by dragging the mouse
  48. * @author nehon
  49. */
  50. public class ChaseCamera implements ActionListener, AnalogListener, Control {
  51. protected Spatial target = null;
  52. protected float minVerticalRotation = 0.00f;
  53. protected float maxVerticalRotation = FastMath.PI / 2;
  54. protected float minDistance = 1.0f;
  55. protected float maxDistance = 40.0f;
  56. protected float distance = 20;
  57. protected float zoomSpeed = 2f;
  58. protected float rotationSpeed = 1.0f;
  59. protected float rotation = 0;
  60. protected float trailingRotationInertia = 0.05f;
  61. protected float zoomSensitivity = 5f;
  62. protected float rotationSensitivity = 5f;
  63. protected float chasingSensitivity = 5f;
  64. protected float trailingSensitivity = 0.5f;
  65. protected float vRotation = FastMath.PI / 6;
  66. protected boolean smoothMotion = false;
  67. protected boolean trailingEnabled = true;
  68. protected float rotationLerpFactor = 0;
  69. protected float trailingLerpFactor = 0;
  70. protected boolean rotating = false;
  71. protected boolean vRotating = false;
  72. protected float targetRotation = rotation;
  73. protected InputManager inputManager;
  74. protected Vector3f initialUpVec;
  75. protected float targetVRotation = vRotation;
  76. protected float vRotationLerpFactor = 0;
  77. protected float targetDistance = distance;
  78. protected float distanceLerpFactor = 0;
  79. protected boolean zooming = false;
  80. protected boolean trailing = false;
  81. protected boolean chasing = false;
  82. protected boolean veryCloseRotation = true;
  83. protected boolean canRotate;
  84. protected float offsetDistance = 0.002f;
  85. protected Vector3f prevPos;
  86. protected boolean targetMoves = false;
  87. protected boolean enabled = true;
  88. protected Camera cam = null;
  89. protected final Vector3f targetDir = new Vector3f();
  90. protected float previousTargetRotation;
  91. protected final Vector3f pos = new Vector3f();
  92. protected Vector3f targetLocation = new Vector3f(0, 0, 0);
  93. protected boolean dragToRotate = true;
  94. protected Vector3f lookAtOffset = new Vector3f(0, 0, 0);
  95. protected boolean leftClickRotate = true;
  96. protected boolean rightClickRotate = true;
  97. protected Vector3f temp = new Vector3f(0, 0, 0);
  98. protected boolean invertYaxis = false;
  99. protected boolean invertXaxis = false;
  100. protected final static String ChaseCamDown = "ChaseCamDown";
  101. protected final static String ChaseCamUp = "ChaseCamUp";
  102. protected final static String ChaseCamZoomIn = "ChaseCamZoomIn";
  103. protected final static String ChaseCamZoomOut = "ChaseCamZoomOut";
  104. protected final static String ChaseCamMoveLeft = "ChaseCamMoveLeft";
  105. protected final static String ChaseCamMoveRight = "ChaseCamMoveRight";
  106. protected final static String ChaseCamToggleRotate = "ChaseCamToggleRotate";
  107. protected boolean zoomin;
  108. protected boolean hideCursorOnRotate = true;
  109. /**
  110. * Constructs the chase camera
  111. * @param cam the application camera
  112. * @param target the spatial to follow
  113. */
  114. public ChaseCamera(Camera cam, final Spatial target) {
  115. this(cam);
  116. target.addControl(this);
  117. }
  118. /**
  119. * Constructs the chase camera
  120. * if you use this constructor you have to attach the cam later to a spatial
  121. * doing spatial.addControl(chaseCamera);
  122. * @param cam the application camera
  123. */
  124. public ChaseCamera(Camera cam) {
  125. this.cam = cam;
  126. initialUpVec = cam.getUp().clone();
  127. }
  128. /**
  129. * Constructs the chase camera, and registers inputs
  130. * if you use this constructor you have to attach the cam later to a spatial
  131. * doing spatial.addControl(chaseCamera);
  132. * @param cam the application camera
  133. * @param inputManager the inputManager of the application to register inputs
  134. */
  135. public ChaseCamera(Camera cam, InputManager inputManager) {
  136. this(cam);
  137. registerWithInput(inputManager);
  138. }
  139. /**
  140. * Constructs the chase camera, and registers inputs
  141. * @param cam the application camera
  142. * @param target the spatial to follow
  143. * @param inputManager the inputManager of the application to register inputs
  144. */
  145. public ChaseCamera(Camera cam, final Spatial target, InputManager inputManager) {
  146. this(cam, target);
  147. registerWithInput(inputManager);
  148. }
  149. public void onAction(String name, boolean keyPressed, float tpf) {
  150. if (dragToRotate) {
  151. if (name.equals(ChaseCamToggleRotate) && enabled) {
  152. if (keyPressed) {
  153. canRotate = true;
  154. if (hideCursorOnRotate) {
  155. inputManager.setCursorVisible(false);
  156. }
  157. } else {
  158. canRotate = false;
  159. if (hideCursorOnRotate) {
  160. inputManager.setCursorVisible(true);
  161. }
  162. }
  163. }
  164. }
  165. }
  166. public void onAnalog(String name, float value, float tpf) {
  167. if (name.equals(ChaseCamMoveLeft)) {
  168. rotateCamera(-value);
  169. } else if (name.equals(ChaseCamMoveRight)) {
  170. rotateCamera(value);
  171. } else if (name.equals(ChaseCamUp)) {
  172. vRotateCamera(value);
  173. } else if (name.equals(ChaseCamDown)) {
  174. vRotateCamera(-value);
  175. } else if (name.equals(ChaseCamZoomIn)) {
  176. zoomCamera(-value);
  177. if (zoomin == false) {
  178. distanceLerpFactor = 0;
  179. }
  180. zoomin = true;
  181. } else if (name.equals(ChaseCamZoomOut)) {
  182. zoomCamera(+value);
  183. if (zoomin == true) {
  184. distanceLerpFactor = 0;
  185. }
  186. zoomin = false;
  187. }
  188. }
  189. /**
  190. * Registers inputs with the input manager
  191. * @param inputManager
  192. */
  193. public final void registerWithInput(InputManager inputManager) {
  194. String[] inputs = {ChaseCamToggleRotate,
  195. ChaseCamDown,
  196. ChaseCamUp,
  197. ChaseCamMoveLeft,
  198. ChaseCamMoveRight,
  199. ChaseCamZoomIn,
  200. ChaseCamZoomOut};
  201. this.inputManager = inputManager;
  202. if (!invertYaxis) {
  203. inputManager.addMapping(ChaseCamDown, new MouseAxisTrigger(MouseInput.AXIS_Y, true));
  204. inputManager.addMapping(ChaseCamUp, new MouseAxisTrigger(MouseInput.AXIS_Y, false));
  205. } else {
  206. inputManager.addMapping(ChaseCamDown, new MouseAxisTrigger(MouseInput.AXIS_Y, false));
  207. inputManager.addMapping(ChaseCamUp, new MouseAxisTrigger(MouseInput.AXIS_Y, true));
  208. }
  209. inputManager.addMapping(ChaseCamZoomIn, new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false));
  210. inputManager.addMapping(ChaseCamZoomOut, new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true));
  211. if (!invertXaxis) {
  212. inputManager.addMapping(ChaseCamMoveLeft, new MouseAxisTrigger(MouseInput.AXIS_X, true));
  213. inputManager.addMapping(ChaseCamMoveRight, new MouseAxisTrigger(MouseInput.AXIS_X, false));
  214. } else {
  215. inputManager.addMapping(ChaseCamMoveLeft, new MouseAxisTrigger(MouseInput.AXIS_X, false));
  216. inputManager.addMapping(ChaseCamMoveRight, new MouseAxisTrigger(MouseInput.AXIS_X, true));
  217. }
  218. inputManager.addMapping(ChaseCamToggleRotate, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
  219. inputManager.addMapping(ChaseCamToggleRotate, new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
  220. inputManager.addListener(this, inputs);
  221. }
  222. /**
  223. * Sets custom triggers for toggleing the rotation of the cam
  224. * deafult are
  225. * new MouseButtonTrigger(MouseInput.BUTTON_LEFT) left mouse button
  226. * new MouseButtonTrigger(MouseInput.BUTTON_RIGHT) right mouse button
  227. * @param triggers
  228. */
  229. public void setToggleRotationTrigger(Trigger... triggers) {
  230. inputManager.deleteMapping(ChaseCamToggleRotate);
  231. inputManager.addMapping(ChaseCamToggleRotate, triggers);
  232. inputManager.addListener(this, ChaseCamToggleRotate);
  233. }
  234. /**
  235. * Sets custom triggers for zomming in the cam
  236. * default is
  237. * new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true) mouse wheel up
  238. * @param triggers
  239. */
  240. public void setZoomInTrigger(Trigger... triggers) {
  241. inputManager.deleteMapping(ChaseCamZoomIn);
  242. inputManager.addMapping(ChaseCamZoomIn, triggers);
  243. inputManager.addListener(this, ChaseCamZoomIn);
  244. }
  245. /**
  246. * Sets custom triggers for zomming out the cam
  247. * default is
  248. * new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false) mouse wheel down
  249. * @param triggers
  250. */
  251. public void setZoomOutTrigger(Trigger... triggers) {
  252. inputManager.deleteMapping(ChaseCamZoomOut);
  253. inputManager.addMapping(ChaseCamZoomOut, triggers);
  254. inputManager.addListener(this, ChaseCamZoomOut);
  255. }
  256. protected void computePosition() {
  257. float hDistance = (distance) * FastMath.sin((FastMath.PI / 2) - vRotation);
  258. pos.set(hDistance * FastMath.cos(rotation), (distance) * FastMath.sin(vRotation), hDistance * FastMath.sin(rotation));
  259. pos.addLocal(target.getWorldTranslation());
  260. }
  261. //rotate the camera around the target on the horizontal plane
  262. protected void rotateCamera(float value) {
  263. if (!canRotate || !enabled) {
  264. return;
  265. }
  266. rotating = true;
  267. targetRotation += value * rotationSpeed;
  268. }
  269. //move the camera toward or away the target
  270. protected void zoomCamera(float value) {
  271. if (!enabled) {
  272. return;
  273. }
  274. zooming = true;
  275. targetDistance += value * zoomSpeed;
  276. if (targetDistance > maxDistance) {
  277. targetDistance = maxDistance;
  278. }
  279. if (targetDistance < minDistance) {
  280. targetDistance = minDistance;
  281. }
  282. if (veryCloseRotation) {
  283. if ((targetVRotation < minVerticalRotation) && (targetDistance > (minDistance + 1.0f))) {
  284. targetVRotation = minVerticalRotation;
  285. }
  286. }
  287. }
  288. //rotate the camera around the target on the vertical plane
  289. protected void vRotateCamera(float value) {
  290. if (!canRotate || !enabled) {
  291. return;
  292. }
  293. vRotating = true;
  294. float lastGoodRot = targetVRotation;
  295. targetVRotation += value * rotationSpeed;
  296. if (targetVRotation > maxVerticalRotation) {
  297. targetVRotation = lastGoodRot;
  298. }
  299. if (veryCloseRotation) {
  300. if ((targetVRotation < minVerticalRotation) && (targetDistance > (minDistance + 1.0f))) {
  301. targetVRotation = minVerticalRotation;
  302. } else if (targetVRotation < -FastMath.DEG_TO_RAD * 90) {
  303. targetVRotation = lastGoodRot;
  304. }
  305. } else {
  306. if ((targetVRotation < minVerticalRotation)) {
  307. targetVRotation = lastGoodRot;
  308. }
  309. }
  310. }
  311. /**
  312. * Updates the camera, should only be called internally
  313. */
  314. protected void updateCamera(float tpf) {
  315. if (enabled) {
  316. targetLocation.set(target.getWorldTranslation()).addLocal(lookAtOffset);
  317. if (smoothMotion) {
  318. //computation of target direction
  319. targetDir.set(targetLocation).subtractLocal(prevPos);
  320. float dist = targetDir.length();
  321. //Low pass filtering on the target postition to avoid shaking when physics are enabled.
  322. if (offsetDistance < dist) {
  323. //target moves, start chasing.
  324. chasing = true;
  325. //target moves, start trailing if it has to.
  326. if (trailingEnabled) {
  327. trailing = true;
  328. }
  329. //target moves...
  330. targetMoves = true;
  331. } else {
  332. //if target was moving, we compute a slight offset in rotation to avoid a rought stop of the cam
  333. //We do not if the player is rotationg the cam
  334. if (targetMoves && !canRotate) {
  335. if (targetRotation - rotation > trailingRotationInertia) {
  336. targetRotation = rotation + trailingRotationInertia;
  337. } else if (targetRotation - rotation < -trailingRotationInertia) {
  338. targetRotation = rotation - trailingRotationInertia;
  339. }
  340. }
  341. //Target stops
  342. targetMoves = false;
  343. }
  344. //the user is rotating the cam by dragging the mouse
  345. if (canRotate) {
  346. //reseting the trailing lerp factor
  347. trailingLerpFactor = 0;
  348. //stop trailing user has the control
  349. trailing = false;
  350. }
  351. if (trailingEnabled && trailing) {
  352. if (targetMoves) {
  353. //computation if the inverted direction of the target
  354. Vector3f a = targetDir.negate().normalizeLocal();
  355. //the x unit vector
  356. Vector3f b = Vector3f.UNIT_X;
  357. //2d is good enough
  358. a.y = 0;
  359. //computation of the rotation angle between the x axis and the trail
  360. if (targetDir.z > 0) {
  361. targetRotation = FastMath.TWO_PI - FastMath.acos(a.dot(b));
  362. } else {
  363. targetRotation = FastMath.acos(a.dot(b));
  364. }
  365. if (targetRotation - rotation > FastMath.PI || targetRotation - rotation < -FastMath.PI) {
  366. targetRotation -= FastMath.TWO_PI;
  367. }
  368. //if there is an important change in the direction while trailing reset of the lerp factor to avoid jumpy movements
  369. if (targetRotation != previousTargetRotation && FastMath.abs(targetRotation - previousTargetRotation) > FastMath.PI / 8) {
  370. trailingLerpFactor = 0;
  371. }
  372. previousTargetRotation = targetRotation;
  373. }
  374. //computing lerp factor
  375. trailingLerpFactor = Math.min(trailingLerpFactor + tpf * tpf * trailingSensitivity, 1);
  376. //computing rotation by linear interpolation
  377. rotation = FastMath.interpolateLinear(trailingLerpFactor, rotation, targetRotation);
  378. //if the rotation is near the target rotation we're good, that's over
  379. if (targetRotation + 0.01f >= rotation && targetRotation - 0.01f <= rotation) {
  380. trailing = false;
  381. trailingLerpFactor = 0;
  382. }
  383. }
  384. //linear interpolation of the distance while chasing
  385. if (chasing) {
  386. distance = temp.set(targetLocation).subtractLocal(cam.getLocation()).length();
  387. distanceLerpFactor = Math.min(distanceLerpFactor + (tpf * tpf * chasingSensitivity * 0.05f), 1);
  388. distance = FastMath.interpolateLinear(distanceLerpFactor, distance, targetDistance);
  389. if (targetDistance + 0.01f >= distance && targetDistance - 0.01f <= distance) {
  390. distanceLerpFactor = 0;
  391. chasing = false;
  392. }
  393. }
  394. //linear interpolation of the distance while zooming
  395. if (zooming) {
  396. distanceLerpFactor = Math.min(distanceLerpFactor + (tpf * tpf * zoomSensitivity), 1);
  397. distance = FastMath.interpolateLinear(distanceLerpFactor, distance, targetDistance);
  398. if (targetDistance + 0.1f >= distance && targetDistance - 0.1f <= distance) {
  399. zooming = false;
  400. distanceLerpFactor = 0;
  401. }
  402. }
  403. //linear interpolation of the rotation while rotating horizontally
  404. if (rotating) {
  405. rotationLerpFactor = Math.min(rotationLerpFactor + tpf * tpf * rotationSensitivity, 1);
  406. rotation = FastMath.interpolateLinear(rotationLerpFactor, rotation, targetRotation);
  407. if (targetRotation + 0.01f >= rotation && targetRotation - 0.01f <= rotation) {
  408. rotating = false;
  409. rotationLerpFactor = 0;
  410. }
  411. }
  412. //linear interpolation of the rotation while rotating vertically
  413. if (vRotating) {
  414. vRotationLerpFactor = Math.min(vRotationLerpFactor + tpf * tpf * rotationSensitivity, 1);
  415. vRotation = FastMath.interpolateLinear(vRotationLerpFactor, vRotation, targetVRotation);
  416. if (targetVRotation + 0.01f >= vRotation && targetVRotation - 0.01f <= vRotation) {
  417. vRotating = false;
  418. vRotationLerpFactor = 0;
  419. }
  420. }
  421. //computing the position
  422. computePosition();
  423. //setting the position at last
  424. cam.setLocation(pos.addLocal(lookAtOffset));
  425. } else {
  426. //easy no smooth motion
  427. vRotation = targetVRotation;
  428. rotation = targetRotation;
  429. distance = targetDistance;
  430. computePosition();
  431. cam.setLocation(pos.addLocal(lookAtOffset));
  432. }
  433. //keeping track on the previous position of the target
  434. prevPos.set(targetLocation);
  435. //the cam looks at the target
  436. cam.lookAt(targetLocation, initialUpVec);
  437. }
  438. }
  439. /**
  440. * Return the enabled/disabled state of the camera
  441. * @return true if the camera is enabled
  442. */
  443. public boolean isEnabled() {
  444. return enabled;
  445. }
  446. /**
  447. * Enable or disable the camera
  448. * @param enabled true to enable
  449. */
  450. public void setEnabled(boolean enabled) {
  451. this.enabled = enabled;
  452. if (!enabled) {
  453. canRotate = false; // reset this flag in-case it was on before
  454. }
  455. }
  456. /**
  457. * Returns the max zoom distance of the camera (default is 40)
  458. * @return maxDistance
  459. */
  460. public float getMaxDistance() {
  461. return maxDistance;
  462. }
  463. /**
  464. * Sets the max zoom distance of the camera (default is 40)
  465. * @param maxDistance
  466. */
  467. public void setMaxDistance(float maxDistance) {
  468. this.maxDistance = maxDistance;
  469. if (maxDistance < distance) {
  470. zoomCamera(maxDistance - distance);
  471. }
  472. }
  473. /**
  474. * Returns the min zoom distance of the camera (default is 1)
  475. * @return minDistance
  476. */
  477. public float getMinDistance() {
  478. return minDistance;
  479. }
  480. /**
  481. * Sets the min zoom distance of the camera (default is 1)
  482. * @return minDistance
  483. */
  484. public void setMinDistance(float minDistance) {
  485. this.minDistance = minDistance;
  486. if (minDistance > distance) {
  487. zoomCamera(distance - minDistance);
  488. }
  489. }
  490. /**
  491. * clone this camera for a spatial
  492. * @param spatial
  493. * @return
  494. */
  495. public Control cloneForSpatial(Spatial spatial) {
  496. ChaseCamera cc = new ChaseCamera(cam, spatial, inputManager);
  497. cc.setMaxDistance(getMaxDistance());
  498. cc.setMinDistance(getMinDistance());
  499. return cc;
  500. }
  501. /**
  502. * Sets the spacial for the camera control, should only be used internally
  503. * @param spatial
  504. */
  505. public void setSpatial(Spatial spatial) {
  506. target = spatial;
  507. if (spatial == null) {
  508. return;
  509. }
  510. computePosition();
  511. prevPos = new Vector3f(target.getWorldTranslation());
  512. cam.setLocation(pos);
  513. }
  514. /**
  515. * update the camera control, should only be used internally
  516. * @param tpf
  517. */
  518. public void update(float tpf) {
  519. updateCamera(tpf);
  520. }
  521. /**
  522. * renders the camera control, should only be used internally
  523. * @param rm
  524. * @param vp
  525. */
  526. public void render(RenderManager rm, ViewPort vp) {
  527. //nothing to render
  528. }
  529. /**
  530. * Write the camera
  531. * @param ex the exporter
  532. * @throws IOException
  533. */
  534. public void write(JmeExporter ex) throws IOException {
  535. OutputCapsule capsule = ex.getCapsule(this);
  536. capsule.write(maxDistance, "maxDistance", 40);
  537. capsule.write(minDistance, "minDistance", 1);
  538. }
  539. /**
  540. * Read the camera
  541. * @param im
  542. * @throws IOException
  543. */
  544. public void read(JmeImporter im) throws IOException {
  545. InputCapsule ic = im.getCapsule(this);
  546. maxDistance = ic.readFloat("maxDistance", 40);
  547. minDistance = ic.readFloat("minDistance", 1);
  548. }
  549. /**
  550. * @return The maximal vertical rotation angle in radian of the camera around the target
  551. */
  552. public float getMaxVerticalRotation() {
  553. return maxVerticalRotation;
  554. }
  555. /**
  556. * Sets the maximal vertical rotation angle in radian of the camera around the target. Default is Pi/2;
  557. * @param maxVerticalRotation
  558. */
  559. public void setMaxVerticalRotation(float maxVerticalRotation) {
  560. this.maxVerticalRotation = maxVerticalRotation;
  561. }
  562. /**
  563. *
  564. * @return The minimal vertical rotation angle in radian of the camera around the target
  565. */
  566. public float getMinVerticalRotation() {
  567. return minVerticalRotation;
  568. }
  569. /**
  570. * Sets the minimal vertical rotation angle in radian of the camera around the target default is 0;
  571. * @param minHeight
  572. */
  573. public void setMinVerticalRotation(float minHeight) {
  574. this.minVerticalRotation = minHeight;
  575. }
  576. /**
  577. * @return True is smooth motion is enabled for this chase camera
  578. */
  579. public boolean isSmoothMotion() {
  580. return smoothMotion;
  581. }
  582. /**
  583. * Enables smooth motion for this chase camera
  584. * @param smoothMotion
  585. */
  586. public void setSmoothMotion(boolean smoothMotion) {
  587. this.smoothMotion = smoothMotion;
  588. }
  589. /**
  590. * returns the chasing sensitivity
  591. * @return
  592. */
  593. public float getChasingSensitivity() {
  594. return chasingSensitivity;
  595. }
  596. /**
  597. *
  598. * Sets the chasing sensitivity, the lower the value the slower the camera will follow the target when it moves
  599. * default is 5
  600. * Only has an effect if smoothMotion is set to true and trailing is enabled
  601. * @param chasingSensitivity
  602. */
  603. public void setChasingSensitivity(float chasingSensitivity) {
  604. this.chasingSensitivity = chasingSensitivity;
  605. }
  606. /**
  607. * Returns the rotation sensitivity
  608. * @return
  609. */
  610. public float getRotationSensitivity() {
  611. return rotationSensitivity;
  612. }
  613. /**
  614. * Sets the rotation sensitivity, the lower the value the slower the camera will rotates around the target when draging with the mouse
  615. * default is 5, values over 5 should have no effect.
  616. * If you want a significant slow down try values below 1.
  617. * Only has an effect if smoothMotion is set to true
  618. * @param rotationSensitivity
  619. */
  620. public void setRotationSensitivity(float rotationSensitivity) {
  621. this.rotationSensitivity = rotationSensitivity;
  622. }
  623. /**
  624. * returns true if the trailing is enabled
  625. * @return
  626. */
  627. public boolean isTrailingEnabled() {
  628. return trailingEnabled;
  629. }
  630. /**
  631. * Enable the camera trailing : The camera smoothly go in the targets trail when it moves.
  632. * Only has an effect if smoothMotion is set to true
  633. * @param trailingEnabled
  634. */
  635. public void setTrailingEnabled(boolean trailingEnabled) {
  636. this.trailingEnabled = trailingEnabled;
  637. }
  638. /**
  639. *
  640. * returns the trailing rotation inertia
  641. * @return
  642. */
  643. public float getTrailingRotationInertia() {
  644. return trailingRotationInertia;
  645. }
  646. /**
  647. * Sets the trailing rotation inertia : default is 0.1. This prevent the camera to roughtly stop when the target stops moving
  648. * before the camera reached the trail position.
  649. * Only has an effect if smoothMotion is set to true and trailing is enabled
  650. * @param trailingRotationInertia
  651. */
  652. public void setTrailingRotationInertia(float trailingRotationInertia) {
  653. this.trailingRotationInertia = trailingRotationInertia;
  654. }
  655. /**
  656. * returns the trailing sensitivity
  657. * @return
  658. */
  659. public float getTrailingSensitivity() {
  660. return trailingSensitivity;
  661. }
  662. /**
  663. * Only has an effect if smoothMotion is set to true and trailing is enabled
  664. * Sets the trailing sensitivity, the lower the value, the slower the camera will go in the target trail when it moves.
  665. * default is 0.5;
  666. * @param trailingSensitivity
  667. */
  668. public void setTrailingSensitivity(float trailingSensitivity) {
  669. this.trailingSensitivity = trailingSensitivity;
  670. }
  671. /**
  672. * returns the zoom sensitivity
  673. * @return
  674. */
  675. public float getZoomSensitivity() {
  676. return zoomSensitivity;
  677. }
  678. /**
  679. * Sets the zoom sensitivity, the lower the value, the slower the camera will zoom in and out.
  680. * default is 5.
  681. * @param zoomSensitivity
  682. */
  683. public void setZoomSensitivity(float zoomSensitivity) {
  684. this.zoomSensitivity = zoomSensitivity;
  685. }
  686. /**
  687. * Sets the default distance at start of applicaiton
  688. * @param defaultDistance
  689. */
  690. public void setDefaultDistance(float defaultDistance) {
  691. distance = defaultDistance;
  692. targetDistance = distance;
  693. }
  694. /**
  695. * sets the default horizontal rotation in radian of the camera at start of the application
  696. * @param angleInRad
  697. */
  698. public void setDefaultHorizontalRotation(float angleInRad) {
  699. rotation = angleInRad;
  700. targetRotation = angleInRad;
  701. }
  702. /**
  703. * sets the default vertical rotation in radian of the camera at start of the application
  704. * @param angleInRad
  705. */
  706. public void setDefaultVerticalRotation(float angleInRad) {
  707. vRotation = angleInRad;
  708. targetVRotation = angleInRad;
  709. }
  710. /**
  711. * @return If drag to rotate feature is enabled.
  712. *
  713. * @see FlyByCamera#setDragToRotate(boolean)
  714. */
  715. public boolean isDragToRotate() {
  716. return dragToRotate;
  717. }
  718. /**
  719. * @param dragToRotate When true, the user must hold the mouse button
  720. * and drag over the screen to rotate the camera, and the cursor is
  721. * visible until dragged. Otherwise, the cursor is invisible at all times
  722. * and holding the mouse button is not needed to rotate the camera.
  723. * This feature is disabled by default.
  724. */
  725. public void setDragToRotate(boolean dragToRotate) {
  726. this.dragToRotate = dragToRotate;
  727. this.canRotate = !dragToRotate;
  728. inputManager.setCursorVisible(dragToRotate);
  729. }
  730. /**
  731. * @param rotateOnlyWhenClose When this flag is set to false the chase
  732. * camera will always rotate around its spatial independently of their
  733. * distance to one another. If set to true, the chase camera will only
  734. * be allowed to rotated below the "horizon" when the distance is smaller
  735. * than minDistance + 1.0f (when fully zoomed-in).
  736. */
  737. public void setDownRotateOnCloseViewOnly(boolean rotateOnlyWhenClose) {
  738. veryCloseRotation = rotateOnlyWhenClose;
  739. }
  740. /**
  741. * @return True if rotation below the vertical plane of the spatial tied
  742. * to the camera is allowed only when zoomed in at minDistance + 1.0f.
  743. * False if vertical rotation is always allowed.
  744. */
  745. public boolean getDownRotateOnCloseViewOnly() {
  746. return veryCloseRotation;
  747. }
  748. /**
  749. * return the current distance from the camera to the target
  750. * @return
  751. */
  752. public float getDistanceToTarget() {
  753. return distance;
  754. }
  755. /**
  756. * returns the current horizontal rotation around the target in radians
  757. * @return
  758. */
  759. public float getHorizontalRotation() {
  760. return rotation;
  761. }
  762. /**
  763. * returns the current vertical rotation around the target in radians.
  764. * @return
  765. */
  766. public float getVerticalRotation() {
  767. return vRotation;
  768. }
  769. /**
  770. * returns the offset from the target's position where the camera looks at
  771. * @return
  772. */
  773. public Vector3f getLookAtOffset() {
  774. return lookAtOffset;
  775. }
  776. /**
  777. * Sets the offset from the target's position where the camera looks at
  778. * @param lookAtOffset
  779. */
  780. public void setLookAtOffset(Vector3f lookAtOffset) {
  781. this.lookAtOffset = lookAtOffset;
  782. }
  783. /**
  784. * Sets the up vector of the camera used for the lookAt on the target
  785. * @param up
  786. */
  787. public void setUpVector(Vector3f up) {
  788. initialUpVec = up;
  789. }
  790. /**
  791. * Returns the up vector of the camera used for the lookAt on the target
  792. * @return
  793. */
  794. public Vector3f getUpVector() {
  795. return initialUpVec;
  796. }
  797. public boolean isHideCursorOnRotate() {
  798. return hideCursorOnRotate;
  799. }
  800. public void setHideCursorOnRotate(boolean hideCursorOnRotate) {
  801. this.hideCursorOnRotate = hideCursorOnRotate;
  802. }
  803. /**
  804. * invert the vertical axis movement of the mouse
  805. * @param invertYaxis
  806. */
  807. public void setInvertVerticalAxis(boolean invertYaxis) {
  808. this.invertYaxis = invertYaxis;
  809. inputManager.deleteMapping(ChaseCamDown);
  810. inputManager.deleteMapping(ChaseCamUp);
  811. if (!invertYaxis) {
  812. inputManager.addMapping(ChaseCamDown, new MouseAxisTrigger(MouseInput.AXIS_Y, true));
  813. inputManager.addMapping(ChaseCamUp, new MouseAxisTrigger(MouseInput.AXIS_Y, false));
  814. } else {
  815. inputManager.addMapping(ChaseCamDown, new MouseAxisTrigger(MouseInput.AXIS_Y, false));
  816. inputManager.addMapping(ChaseCamUp, new MouseAxisTrigger(MouseInput.AXIS_Y, true));
  817. }
  818. inputManager.addListener(this, ChaseCamDown, ChaseCamUp);
  819. }
  820. /**
  821. * invert the Horizontal axis movement of the mouse
  822. * @param invertXaxis
  823. */
  824. public void setInvertHorizontalAxis(boolean invertXaxis) {
  825. this.invertXaxis = invertXaxis;
  826. inputManager.deleteMapping(ChaseCamMoveLeft);
  827. inputManager.deleteMapping(ChaseCamMoveRight);
  828. if (!invertXaxis) {
  829. inputManager.addMapping(ChaseCamMoveLeft, new MouseAxisTrigger(MouseInput.AXIS_X, true));
  830. inputManager.addMapping(ChaseCamMoveRight, new MouseAxisTrigger(MouseInput.AXIS_X, false));
  831. } else {
  832. inputManager.addMapping(ChaseCamMoveLeft, new MouseAxisTrigger(MouseInput.AXIS_X, false));
  833. inputManager.addMapping(ChaseCamMoveRight, new MouseAxisTrigger(MouseInput.AXIS_X, true));
  834. }
  835. inputManager.addListener(this, ChaseCamMoveLeft, ChaseCamMoveRight);
  836. }
  837. }