hello_physics.html 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]--><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Asciidoctor 1.5.4"><meta name="keywords" content="beginner, intro, physics, documentation, input, model, control"><title>jMonkeyEngine 3 Tutorial (13) - Hello Physics</title><link rel="stylesheet" href="./asciidoctor.css">
  2. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css">
  3. <link rel="stylesheet" href="./coderay-asciidoctor.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css"><link rel="stylesheet" href="/home/travis/build/jMonkeyEngine/wiki/build/asciidoc/html5/jme3/beginner/twemoji-awesome.css"></head><body class="article toc2 toc-left"><div id="header"><div id="toolbar"><a href="https://github.com/jMonkeyEngine/wiki/edit/master/src/docs/asciidoc/jme3/beginner/hello_physics.adoc"><i class="fa fa-pencil-square" aria-hidden="true"></i></a><a href="https://github.com/jMonkeyEngine/wiki/new/master/src/docs/asciidoc/jme3/beginner/"><i class="fa fa-plus-square" aria-hidden="true"></i></a><input dir="auto" style="position: relative; vertical-align: top;" spellcheck="false" autocomplete="off" class="searchbox__input aa-input" id="doc-search" name="search" placeholder="Search in the doc" required="required" type="search"></div><h1>jMonkeyEngine 3 Tutorial (13) - Hello Physics</h1><div class="details"><span class="author" id="author"></span><br><span id="revnumber">version ,</span> <span id="revdate">2016/03/17 20:48</span></div><div id="toc" class="toc2"><div id="toctitle">Table of Contents</div><ul class="sectlevel1"><li><a href="#sample-code">Sample Code</a></li><li><a href="#a-basic-physics-application">A Basic Physics Application</a></li><li><a href="#creating-bricks-and-cannon-balls">Creating Bricks and Cannon Balls</a><ul class="sectlevel2"><li><a href="#geometries">Geometries</a></li><li><a href="#rigidbodycontrol-brick">RigidBodyControl: Brick</a></li><li><a href="#rigidbodycontrol-cannonball">RigidBodyControl: Cannonball</a></li><li><a href="#rigidbodycontrol-floor">RigidBodyControl: Floor</a></li></ul></li><li><a href="#creating-the-scene">Creating the Scene</a></li><li><a href="#the-cannon-ball-shooting-action">The Cannon Ball Shooting Action</a></li><li><a href="#moving-a-physical-spatial">Moving a Physical Spatial</a></li><li><a href="#excercises">Excercises</a><ul class="sectlevel2"><li><a href="#exercise-1-debug-shapes">Exercise 1: Debug Shapes</a></li><li><a href="#exercise-2-no-mo-static">Exercise 2: No Mo' Static</a></li><li><a href="#exercise-3-behind-the-curtain">Exercise 3: Behind the Curtain</a></li></ul></li><li><a href="#conclusion">Conclusion</a></li></ul></div></div><div id="content"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p>Previous: <a href="../../jme3/beginner/hello_effects.html">Hello Effects</a>,
  4. Next: <a href="../../jme3.html">JME 3 documentation</a></p></div>
  5. <div class="paragraph"><p>Do you remember the <a href="../../jme3/beginner/hello_collision.html">Hello Collision</a> tutorial where you made the model of a town solid and walked through it in a first-person perspective? Then you may remember that, for the simulation of physical forces, jME3 integrates the <a href="http://jbullet.advel.cz/">jBullet</a> library.</p></div>
  6. <div class="paragraph"><p>Apart from making models “solid, the most common use cases for physics in 3D games are:</p></div>
  7. <div class="ulist"><ul><li><p>Driving vehicles with suspensions, tyre friction, ramp jumping, drifting – Example: car racers</p></li><li><p>Rolling and bouncing balls – Example: pong, pool billiard, bowling</p></li><li><p>Sliding and falling boxes – Example: Breakout, Arkanoid</p></li><li><p>Exposing objects to forces and gravity – Example: spaceships or zero-g flight</p></li><li><p>Animating ragdolls – Example: “realistic character simulations</p></li><li><p>Swinging pendulums, rope bridges, flexible chains, and much more…</p></li></ul></div>
  8. <div class="paragraph"><p>All these physical properties can be simulated in JME3. Let&#8217;s have a look at a simulation of physical forces in this example where you shoot cannon balls at a brick wall.</p></div>
  9. <div style="text-align: center;" class="imageblock"><div class="content"><img src="../../jme3/beginner/beginner-physics.png" alt="beginner-physics.png" width="360" height="291"></div></div>
  10. <div class="admonitionblock tip"><table><tr><td class="icon"><i class="fa icon-tip" title="Tip"></i></td><td class="content"><div class="paragraph"><p>To use the example assets in a new jMonkeyEngine SDK project, right-click your project, select “Properties, go to “Libraries, press “Add Library and add the “jme3-test-data library.</p></div></td></tr></table></div></div></div>
  11. <div class="sect1"><h2 id="sample-code">Sample Code</h2><div class="sectionbody"><div class="paragraph"><p>Thanks to double1984 for contributing this fun sample!</p></div>
  12. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">jme3test.helloworld</span>;
  13. <span class="keyword">import</span> <span class="include">com.jme3.app.SimpleApplication</span>;
  14. <span class="keyword">import</span> <span class="include">com.jme3.asset.TextureKey</span>;
  15. <span class="keyword">import</span> <span class="include">com.jme3.bullet.BulletAppState</span>;
  16. <span class="keyword">import</span> <span class="include">com.jme3.bullet.control.RigidBodyControl</span>;
  17. <span class="keyword">import</span> <span class="include">com.jme3.font.BitmapText</span>;
  18. <span class="keyword">import</span> <span class="include">com.jme3.input.MouseInput</span>;
  19. <span class="keyword">import</span> <span class="include">com.jme3.input.controls.ActionListener</span>;
  20. <span class="keyword">import</span> <span class="include">com.jme3.input.controls.MouseButtonTrigger</span>;
  21. <span class="keyword">import</span> <span class="include">com.jme3.material.Material</span>;
  22. <span class="keyword">import</span> <span class="include">com.jme3.math.Vector2f</span>;
  23. <span class="keyword">import</span> <span class="include">com.jme3.math.Vector3f</span>;
  24. <span class="keyword">import</span> <span class="include">com.jme3.scene.Geometry</span>;
  25. <span class="keyword">import</span> <span class="include">com.jme3.scene.shape.Box</span>;
  26. <span class="keyword">import</span> <span class="include">com.jme3.scene.shape.Sphere</span>;
  27. <span class="keyword">import</span> <span class="include">com.jme3.scene.shape.Sphere.TextureMode</span>;
  28. <span class="keyword">import</span> <span class="include">com.jme3.texture.Texture</span>;
  29. <span class="keyword">import</span> <span class="include">com.jme3.texture.Texture.WrapMode</span>;
  30. <span class="comment">/**
  31. * Example 12 - how to give objects physical properties so they bounce and fall.
  32. * @author base code by double1984, updated by zathras
  33. */</span>
  34. <span class="directive">public</span> <span class="type">class</span> <span class="class">HelloPhysics</span> <span class="directive">extends</span> SimpleApplication {
  35. <span class="directive">public</span> <span class="directive">static</span> <span class="type">void</span> main(<span class="predefined-type">String</span> args<span class="type">[]</span>) {
  36. HelloPhysics app = <span class="keyword">new</span> HelloPhysics();
  37. app.start();
  38. }
  39. <span class="comment">/** Prepare the Physics Application State (jBullet) */</span>
  40. <span class="directive">private</span> BulletAppState bulletAppState;
  41. <span class="comment">/** Prepare Materials */</span>
  42. Material wall_mat;
  43. Material stone_mat;
  44. Material floor_mat;
  45. <span class="comment">/** Prepare geometries and physical nodes for bricks and cannon balls. */</span>
  46. <span class="directive">private</span> RigidBodyControl brick_phy;
  47. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">Box</span> box;
  48. <span class="directive">private</span> RigidBodyControl ball_phy;
  49. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> Sphere sphere;
  50. <span class="directive">private</span> RigidBodyControl floor_phy;
  51. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">Box</span> floor;
  52. <span class="comment">/** dimensions used for bricks and wall */</span>
  53. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="type">float</span> brickLength = <span class="float">0.48f</span>;
  54. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="type">float</span> brickWidth = <span class="float">0.24f</span>;
  55. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="type">float</span> brickHeight = <span class="float">0.12f</span>;
  56. <span class="directive">static</span> {
  57. <span class="comment">/** Initialize the cannon ball geometry */</span>
  58. sphere = <span class="keyword">new</span> Sphere(<span class="integer">32</span>, <span class="integer">32</span>, <span class="float">0.4f</span>, <span class="predefined-constant">true</span>, <span class="predefined-constant">false</span>);
  59. sphere.setTextureMode(TextureMode.Projected);
  60. <span class="comment">/** Initialize the brick geometry */</span>
  61. box = <span class="keyword">new</span> <span class="predefined-type">Box</span>(brickLength, brickHeight, brickWidth);
  62. box.scaleTextureCoordinates(<span class="keyword">new</span> Vector2f(<span class="float">1f</span>, <span class="float">.5f</span>));
  63. <span class="comment">/** Initialize the floor geometry */</span>
  64. floor = <span class="keyword">new</span> <span class="predefined-type">Box</span>(<span class="float">10f</span>, <span class="float">0.1f</span>, <span class="float">5f</span>);
  65. floor.scaleTextureCoordinates(<span class="keyword">new</span> Vector2f(<span class="integer">3</span>, <span class="integer">6</span>));
  66. }
  67. <span class="annotation">@Override</span>
  68. <span class="directive">public</span> <span class="type">void</span> simpleInitApp() {
  69. <span class="comment">/** Set up Physics Game */</span>
  70. bulletAppState = <span class="keyword">new</span> BulletAppState();
  71. stateManager.attach(bulletAppState);
  72. <span class="comment">//bulletAppState.getPhysicsSpace().enableDebug(assetManager);</span>
  73. <span class="comment">/** Configure cam to look at scene */</span>
  74. cam.setLocation(<span class="keyword">new</span> Vector3f(<span class="integer">0</span>, <span class="float">4f</span>, <span class="float">6f</span>));
  75. cam.lookAt(<span class="keyword">new</span> Vector3f(<span class="integer">2</span>, <span class="integer">2</span>, <span class="integer">0</span>), Vector3f.UNIT_Y);
  76. <span class="comment">/** Add InputManager action: Left click triggers shooting. */</span>
  77. inputManager.addMapping(<span class="string"><span class="delimiter">&quot;</span><span class="content">shoot</span><span class="delimiter">&quot;</span></span>,
  78. <span class="keyword">new</span> MouseButtonTrigger(MouseInput.BUTTON_LEFT));
  79. inputManager.addListener(actionListener, <span class="string"><span class="delimiter">&quot;</span><span class="content">shoot</span><span class="delimiter">&quot;</span></span>);
  80. <span class="comment">/** Initialize the scene, materials, and physics space */</span>
  81. initMaterials();
  82. initWall();
  83. initFloor();
  84. initCrossHairs();
  85. }
  86. <span class="comment">/**
  87. * Every time the shoot action is triggered, a new cannon ball is produced.
  88. * The ball is set up to fly from the camera position in the camera direction.
  89. */</span>
  90. <span class="directive">private</span> <span class="predefined-type">ActionListener</span> actionListener = <span class="keyword">new</span> <span class="predefined-type">ActionListener</span>() {
  91. <span class="directive">public</span> <span class="type">void</span> onAction(<span class="predefined-type">String</span> name, <span class="type">boolean</span> keyPressed, <span class="type">float</span> tpf) {
  92. <span class="keyword">if</span> (name.equals(<span class="string"><span class="delimiter">&quot;</span><span class="content">shoot</span><span class="delimiter">&quot;</span></span>) &amp;&amp; !keyPressed) {
  93. makeCannonBall();
  94. }
  95. }
  96. };
  97. <span class="comment">/** Initialize the materials used in this scene. */</span>
  98. <span class="directive">public</span> <span class="type">void</span> initMaterials() {
  99. wall_mat = <span class="keyword">new</span> Material(assetManager, <span class="string"><span class="delimiter">&quot;</span><span class="content">Common/MatDefs/Misc/Unshaded.j3md</span><span class="delimiter">&quot;</span></span>);
  100. TextureKey key = <span class="keyword">new</span> TextureKey(<span class="string"><span class="delimiter">&quot;</span><span class="content">Textures/Terrain/BrickWall/BrickWall.jpg</span><span class="delimiter">&quot;</span></span>);
  101. key.setGenerateMips(<span class="predefined-constant">true</span>);
  102. Texture tex = assetManager.loadTexture(key);
  103. wall_mat.setTexture(<span class="string"><span class="delimiter">&quot;</span><span class="content">ColorMap</span><span class="delimiter">&quot;</span></span>, tex);
  104. stone_mat = <span class="keyword">new</span> Material(assetManager, <span class="string"><span class="delimiter">&quot;</span><span class="content">Common/MatDefs/Misc/Unshaded.j3md</span><span class="delimiter">&quot;</span></span>);
  105. TextureKey key2 = <span class="keyword">new</span> TextureKey(<span class="string"><span class="delimiter">&quot;</span><span class="content">Textures/Terrain/Rock/Rock.PNG</span><span class="delimiter">&quot;</span></span>);
  106. key2.setGenerateMips(<span class="predefined-constant">true</span>);
  107. Texture tex2 = assetManager.loadTexture(key2);
  108. stone_mat.setTexture(<span class="string"><span class="delimiter">&quot;</span><span class="content">ColorMap</span><span class="delimiter">&quot;</span></span>, tex2);
  109. floor_mat = <span class="keyword">new</span> Material(assetManager, <span class="string"><span class="delimiter">&quot;</span><span class="content">Common/MatDefs/Misc/Unshaded.j3md</span><span class="delimiter">&quot;</span></span>);
  110. TextureKey key3 = <span class="keyword">new</span> TextureKey(<span class="string"><span class="delimiter">&quot;</span><span class="content">Textures/Terrain/Pond/Pond.jpg</span><span class="delimiter">&quot;</span></span>);
  111. key3.setGenerateMips(<span class="predefined-constant">true</span>);
  112. Texture tex3 = assetManager.loadTexture(key3);
  113. tex3.setWrap(WrapMode.Repeat);
  114. floor_mat.setTexture(<span class="string"><span class="delimiter">&quot;</span><span class="content">ColorMap</span><span class="delimiter">&quot;</span></span>, tex3);
  115. }
  116. <span class="comment">/** Make a solid floor and add it to the scene. */</span>
  117. <span class="directive">public</span> <span class="type">void</span> initFloor() {
  118. Geometry floor_geo = <span class="keyword">new</span> Geometry(<span class="string"><span class="delimiter">&quot;</span><span class="content">Floor</span><span class="delimiter">&quot;</span></span>, floor);
  119. floor_geo.setMaterial(floor_mat);
  120. floor_geo.setLocalTranslation(<span class="integer">0</span>, -<span class="float">0.1f</span>, <span class="integer">0</span>);
  121. <span class="local-variable">this</span>.rootNode.attachChild(floor_geo);
  122. <span class="comment">/* Make the floor physical with mass 0.0f! */</span>
  123. floor_phy = <span class="keyword">new</span> RigidBodyControl(<span class="float">0.0f</span>);
  124. floor_geo.addControl(floor_phy);
  125. bulletAppState.getPhysicsSpace().add(floor_phy);
  126. }
  127. <span class="comment">/** This loop builds a wall out of individual bricks. */</span>
  128. <span class="directive">public</span> <span class="type">void</span> initWall() {
  129. <span class="type">float</span> startpt = brickLength / <span class="integer">4</span>;
  130. <span class="type">float</span> height = <span class="integer">0</span>;
  131. <span class="keyword">for</span> (<span class="type">int</span> j = <span class="integer">0</span>; j &lt; <span class="integer">15</span>; j++) {
  132. <span class="keyword">for</span> (<span class="type">int</span> i = <span class="integer">0</span>; i &lt; <span class="integer">6</span>; i++) {
  133. Vector3f vt =
  134. <span class="keyword">new</span> Vector3f(i * brickLength * <span class="integer">2</span> + startpt, brickHeight + height, <span class="integer">0</span>);
  135. makeBrick(vt);
  136. }
  137. startpt = -startpt;
  138. height += <span class="integer">2</span> * brickHeight;
  139. }
  140. }
  141. <span class="comment">/** This method creates one individual physical brick. */</span>
  142. <span class="directive">public</span> <span class="type">void</span> makeBrick(Vector3f loc) {
  143. <span class="comment">/** Create a brick geometry and attach to scene graph. */</span>
  144. Geometry brick_geo = <span class="keyword">new</span> Geometry(<span class="string"><span class="delimiter">&quot;</span><span class="content">brick</span><span class="delimiter">&quot;</span></span>, box);
  145. brick_geo.setMaterial(wall_mat);
  146. rootNode.attachChild(brick_geo);
  147. <span class="comment">/** Position the brick geometry */</span>
  148. brick_geo.setLocalTranslation(loc);
  149. <span class="comment">/** Make brick physical with a mass &gt; 0.0f. */</span>
  150. brick_phy = <span class="keyword">new</span> RigidBodyControl(<span class="float">2f</span>);
  151. <span class="comment">/** Add physical brick to physics space. */</span>
  152. brick_geo.addControl(brick_phy);
  153. bulletAppState.getPhysicsSpace().add(brick_phy);
  154. }
  155. <span class="comment">/** This method creates one individual physical cannon ball.
  156. * By defaul, the ball is accelerated and flies
  157. * from the camera position in the camera direction.*/</span>
  158. <span class="directive">public</span> <span class="type">void</span> makeCannonBall() {
  159. <span class="comment">/** Create a cannon ball geometry and attach to scene graph. */</span>
  160. Geometry ball_geo = <span class="keyword">new</span> Geometry(<span class="string"><span class="delimiter">&quot;</span><span class="content">cannon ball</span><span class="delimiter">&quot;</span></span>, sphere);
  161. ball_geo.setMaterial(stone_mat);
  162. rootNode.attachChild(ball_geo);
  163. <span class="comment">/** Position the cannon ball */</span>
  164. ball_geo.setLocalTranslation(cam.getLocation());
  165. <span class="comment">/** Make the ball physcial with a mass &gt; 0.0f */</span>
  166. ball_phy = <span class="keyword">new</span> RigidBodyControl(<span class="float">1f</span>);
  167. <span class="comment">/** Add physical ball to physics space. */</span>
  168. ball_geo.addControl(ball_phy);
  169. bulletAppState.getPhysicsSpace().add(ball_phy);
  170. <span class="comment">/** Accelerate the physcial ball to shoot it. */</span>
  171. ball_phy.setLinearVelocity(cam.getDirection().mult(<span class="integer">25</span>));
  172. }
  173. <span class="comment">/** A plus sign used as crosshairs to help the player with aiming.*/</span>
  174. <span class="directive">protected</span> <span class="type">void</span> initCrossHairs() {
  175. guiNode.detachAllChildren();
  176. guiFont = assetManager.loadFont(<span class="string"><span class="delimiter">&quot;</span><span class="content">Interface/Fonts/Default.fnt</span><span class="delimiter">&quot;</span></span>);
  177. BitmapText ch = <span class="keyword">new</span> BitmapText(guiFont, <span class="predefined-constant">false</span>);
  178. ch.setSize(guiFont.getCharSet().getRenderedSize() * <span class="integer">2</span>);
  179. ch.setText(<span class="string"><span class="delimiter">&quot;</span><span class="content">+</span><span class="delimiter">&quot;</span></span>); <span class="comment">// fake crosshairs :)</span>
  180. ch.setLocalTranslation( <span class="comment">// center</span>
  181. settings.getWidth() / <span class="integer">2</span> - guiFont.getCharSet().getRenderedSize() / <span class="integer">3</span> * <span class="integer">2</span>,
  182. settings.getHeight() / <span class="integer">2</span> + ch.getLineHeight() / <span class="integer">2</span>, <span class="integer">0</span>);
  183. guiNode.attachChild(ch);
  184. }
  185. }</code></pre></div></div>
  186. <div class="paragraph"><p>You should see a brick wall. Click to shoot cannon balls. Watch the bricks fall and bounce off one another!</p></div></div></div>
  187. <div class="sect1"><h2 id="a-basic-physics-application">A Basic Physics Application</h2><div class="sectionbody"><div class="paragraph"><p>In the previous tutorials, you used static Geometries (boxes, spheres, and models) that you placed in the scene. Depending on their translation, Geometries can “float in mid-air and even overlap – they are not affected by “gravity and have no physical mass. This tutorial shows how to add physical properties to Geometries.</p></div>
  188. <div class="paragraph"><p>As always, start with a standard com.jme3.app.SimpleApplication. To activate physics, create a com.jme3.bullet.BulletAppState, and and attach it to the SimpleApplication&#8217;s AppState manager.</p></div>
  189. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">HelloPhysics</span> <span class="directive">extends</span> SimpleApplication {
  190. <span class="directive">private</span> BulletAppState bulletAppState;
  191. <span class="directive">public</span> <span class="type">void</span> simpleInitApp() {
  192. bulletAppState = <span class="keyword">new</span> BulletAppState();
  193. stateManager.attach(bulletAppState);
  194. ...
  195. }
  196. ...
  197. }</code></pre></div></div>
  198. <div class="paragraph"><p>The BulletAppState gives the game access to a PhysicsSpace. The PhysicsSpace lets you use com.jme3.bullet.control.PhysicsControls that add physical properties to Nodes.</p></div></div></div>
  199. <div class="sect2"><h3 id="creating-bricks-and-cannon-balls">Creating Bricks and Cannon Balls</h3><div class="sect2"><h3 id="geometries">Geometries</h3><div class="paragraph"><p>In this “shoot at the wall example, you use Geometries such as cannon balls and bricks. Geometries contain meshes, such as Shapes. Let&#8217;s create and initialize some Shapes: Boxes and Spheres.</p></div>
  200. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"> <span class="comment">/** Prepare geometries and physical nodes for bricks and cannon balls. */</span>
  201. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">Box</span> box;
  202. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> Sphere sphere;
  203. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">Box</span> floor;
  204. <span class="comment">/** dimensions used for bricks and wall */</span>
  205. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="type">float</span> brickLength = <span class="float">0.48f</span>;
  206. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="type">float</span> brickWidth = <span class="float">0.24f</span>;
  207. <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="type">float</span> brickHeight = <span class="float">0.12f</span>;
  208. <span class="directive">static</span> {
  209. <span class="comment">/** Initialize the cannon ball geometry */</span>
  210. sphere = <span class="keyword">new</span> Sphere(<span class="integer">32</span>, <span class="integer">32</span>, <span class="float">0.4f</span>, <span class="predefined-constant">true</span>, <span class="predefined-constant">false</span>);
  211. sphere.setTextureMode(TextureMode.Projected);
  212. <span class="comment">/** Initialize the brick geometry */</span>
  213. box = <span class="keyword">new</span> <span class="predefined-type">Box</span>(brickLength, brickHeight, brickWidth);
  214. box.scaleTextureCoordinates(<span class="keyword">new</span> Vector2f(<span class="float">1f</span>, <span class="float">.5f</span>));
  215. <span class="comment">/** Initialize the floor geometry */</span>
  216. floor = <span class="keyword">new</span> <span class="predefined-type">Box</span>(<span class="float">10f</span>, <span class="float">0.1f</span>, <span class="float">5f</span>);
  217. floor.scaleTextureCoordinates(<span class="keyword">new</span> Vector2f(<span class="integer">3</span>, <span class="integer">6</span>));
  218. }</code></pre></div></div></div>
  219. <div class="sect2"><h3 id="rigidbodycontrol-brick">RigidBodyControl: Brick</h3><div class="paragraph"><p>We want to create brick Geometries from those boxes. For each Geometry with physical properties, you create a RigidBodyControl.</p></div>
  220. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"> <span class="directive">private</span> RigidBodyControl brick_phy;</code></pre></div></div>
  221. <div class="paragraph"><p>The custom <code>makeBrick(loc)</code> methods creates individual bricks at the location <code>loc</code>. A brick has the following properties:</p></div>
  222. <div class="ulist"><ul><li><p>It has a visible Geometry <code>brick_geo</code> (Box Shape Geometry).</p></li><li><p>It has physical properties <code>brick_phy</code> (RigidBodyControl)</p></li></ul></div>
  223. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"> <span class="directive">public</span> <span class="type">void</span> makeBrick(Vector3f loc) {
  224. <span class="comment">/** Create a brick geometry and attach to scene graph. */</span>
  225. Geometry brick_geo = <span class="keyword">new</span> Geometry(<span class="string"><span class="delimiter">&quot;</span><span class="content">brick</span><span class="delimiter">&quot;</span></span>, box);
  226. brick_geo.setMaterial(wall_mat);
  227. rootNode.attachChild(brick_geo);
  228. <span class="comment">/** Position the brick geometry */</span>
  229. brick_geo.setLocalTranslation(loc);
  230. <span class="comment">/** Make brick physical with a mass &gt; 0.0f. */</span>
  231. brick_phy = <span class="keyword">new</span> RigidBodyControl(<span class="float">2f</span>);
  232. <span class="comment">/** Add physical brick to physics space. */</span>
  233. brick_geo.addControl(brick_phy);
  234. bulletAppState.getPhysicsSpace().add(brick_phy);
  235. }</code></pre></div></div>
  236. <div class="paragraph"><p>This code sample does the following:</p></div>
  237. <div class="olist arabic"><ol class="arabic"><li><p>You create a brick Geometry brick_geo. A Geometry describes the shape and look of an object.</p><div class="ulist"><ul><li><p>brick_geo has a box shape</p></li><li><p>brick_geo has a brick-colored material.</p></li></ul></div></li><li><p>You attach brick_geo to the rootNode</p></li><li><p>You position brick_geo at <code>loc</code>.</p></li><li><p>You create a RigidBodyControl brick_phy for brick_geo.</p><div class="ulist"><ul><li><p>brick_phy has a mass of 2f.</p></li><li><p>You add brick_phy to brick_geo.</p></li><li><p>You register brick_phy to the PhysicsSpace.</p></li></ul></div></li></ol></div></div>
  238. <div class="sect2"><h3 id="rigidbodycontrol-cannonball">RigidBodyControl: Cannonball</h3><div class="paragraph"><p>You notice that the cannon ball is created in the same way, using the custom <code>makeCannonBall()</code> method. The cannon ball has the following properties:</p></div>
  239. <div class="ulist"><ul><li><p>It has a visible Geometry <code>ball_geo</code> (Sphere Shape Geometry)</p></li><li><p>It has physical properties <code>ball_phy</code> (RigidBodyControl)</p></li></ul></div>
  240. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"> <span class="comment">/** Create a cannon ball geometry and attach to scene graph. */</span>
  241. Geometry ball_geo = <span class="keyword">new</span> Geometry(<span class="string"><span class="delimiter">&quot;</span><span class="content">cannon ball</span><span class="delimiter">&quot;</span></span>, sphere);
  242. ball_geo.setMaterial(stone_mat);
  243. rootNode.attachChild(ball_geo);
  244. <span class="comment">/** Position the cannon ball */</span>
  245. ball_geo.setLocalTranslation(cam.getLocation());
  246. <span class="comment">/** Make the ball physcial with a mass &gt; 0.0f */</span>
  247. ball_phy = <span class="keyword">new</span> RigidBodyControl(<span class="float">1f</span>);
  248. <span class="comment">/** Add physical ball to physics space. */</span>
  249. ball_geo.addControl(ball_phy);
  250. bulletAppState.getPhysicsSpace().add(ball_phy);
  251. <span class="comment">/** Accelerate the physcial ball to shoot it. */</span>
  252. ball_phy.setLinearVelocity(cam.getDirection().mult(<span class="integer">25</span>));</code></pre></div></div>
  253. <div class="paragraph"><p>This code sample does the following:</p></div>
  254. <div class="olist arabic"><ol class="arabic"><li><p>You create a ball Geometry ball_geo. A Geometry describes the shape and look of an object.</p><div class="ulist"><ul><li><p>ball_geo has a sphere shape</p></li><li><p>ball_geo has a stone-colored material.</p></li></ul></div></li><li><p>You attach ball_geo to the rootNode</p></li><li><p>You position ball_geo at the camera location.</p></li><li><p>You create a RigidBodyControl ball_phy for ball_geo.</p><div class="ulist"><ul><li><p>ball_phy has a mass of 1f.</p></li><li><p>You add ball_phy to ball_geo.</p></li><li><p>You register ball_phy to the PhysicsSpace.</p></li></ul></div></li></ol></div>
  255. <div class="paragraph"><p>Since you are shooting cannon balls, the last line accelerates the ball in the direction the camera is looking, with a speed of 25f.</p></div></div>
  256. <div class="sect2"><h3 id="rigidbodycontrol-floor">RigidBodyControl: Floor</h3><div class="paragraph"><p>The (static) floor has one important difference compared to the (dynamic) bricks and cannonballs: <strong>Static objects have a mass of zero.</strong>
  257. As before, you write a custom <code>initFloor()</code> method that creates a flat box with a rock texture that you use as floor. The floor has the following properties:</p></div>
  258. <div class="ulist"><ul><li><p>It has a visible Geometry <code>floor_geo</code> (Box Shape Geometry)</p></li><li><p>It has physical properties <code>floor_phy</code> (RigidBodyControl)</p></li></ul></div>
  259. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"> <span class="directive">public</span> <span class="type">void</span> initFloor() {
  260. Geometry floor_geo = <span class="keyword">new</span> Geometry(<span class="string"><span class="delimiter">&quot;</span><span class="content">Floor</span><span class="delimiter">&quot;</span></span>, floor);
  261. floor_geo.setMaterial(floor_mat);
  262. floor_geo.setLocalTranslation(<span class="integer">0</span>, -<span class="float">0.1f</span>, <span class="integer">0</span>);
  263. <span class="local-variable">this</span>.rootNode.attachChild(floor_geo);
  264. <span class="comment">/* Make the floor physical with mass 0.0f! */</span>
  265. floor_phy = <span class="keyword">new</span> RigidBodyControl(<span class="float">0.0f</span>);
  266. floor_geo.addControl(floor_phy);
  267. bulletAppState.getPhysicsSpace().add(floor_phy);
  268. }</code></pre></div></div>
  269. <div class="paragraph"><p>This code sample does the following:</p></div>
  270. <div class="olist arabic"><ol class="arabic"><li><p>You create a floor Geometry floor_geo. A Geometry describes the shape and look of an object.</p><div class="ulist"><ul><li><p>floor_geo has a box shape</p></li><li><p>floor_geo has a pebble-colored material.</p></li></ul></div></li><li><p>You attach floor_geo to the rootNode</p></li><li><p>You position floor_geo a bit below y=0 (to prevent overlap with other PhysicControl&#8217;ed Spatials).</p></li><li><p>You create a RigidBodyControl floor_phy for floor_geo.</p><div class="ulist"><ul><li><p>floor_phy has a mass of 0f</p></li><li><p>You add floor_phy to floor_geo.</p></li><li><p>You register floor_phy to the PhysicsSpace.</p></li></ul></div></li></ol></div></div></div>
  271. <div class="sect1"><h2 id="creating-the-scene">Creating the Scene</h2><div class="sectionbody"><div class="paragraph"><p>Let&#8217;s have a quick look at the custom helper methods:</p></div>
  272. <div class="ulist"><ul><li><p><code>initMaterial()</code> – This method initializes all the materials we use in this demo.</p></li><li><p><code>initWall()</code> – A double loop that generates a wall by positioning brick objects: 15 rows high with 6 bricks per row. It&#8217;s important to space the physical bricks so they do not overlap.</p></li><li><p><code>initCrossHairs()</code> – This method simply displays a plus sign that you use as crosshairs for aiming. Note that screen elements such as crosshairs are attached to the <code>guiNode</code>, not the <code>rootNode</code>!</p></li><li><p><code>initInputs()</code> – This method sets up the click-to-shoot action.</p></li></ul></div>
  273. <div class="paragraph"><p>These methods are each called once from the <code>simpleInitApp()</code> method at the start of the game. As you see, you can write any number of custom methods to set up your game&#8217;s scene.</p></div></div></div>
  274. <div class="sect1"><h2 id="the-cannon-ball-shooting-action">The Cannon Ball Shooting Action</h2><div class="sectionbody"><div class="paragraph"><p>In the <code>initInputs()</code> method, you add an input mapping that triggers a shoot action when the left mouse button is pressed.</p></div>
  275. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"> <span class="directive">private</span> <span class="type">void</span> initInputs() {
  276. inputManager.addMapping(<span class="string"><span class="delimiter">&quot;</span><span class="content">shoot</span><span class="delimiter">&quot;</span></span>,
  277. <span class="keyword">new</span> MouseButtonTrigger(MouseInput.BUTTON_LEFT));
  278. inputManager.addListener(actionListener, <span class="string"><span class="delimiter">&quot;</span><span class="content">shoot</span><span class="delimiter">&quot;</span></span>);
  279. }</code></pre></div></div>
  280. <div class="paragraph"><p>You define the actual action of shooting a new cannon ball as follows:</p></div>
  281. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"> <span class="directive">private</span> <span class="predefined-type">ActionListener</span> actionListener = <span class="keyword">new</span> <span class="predefined-type">ActionListener</span>() {
  282. <span class="directive">public</span> <span class="type">void</span> onAction(<span class="predefined-type">String</span> name, <span class="type">boolean</span> keyPressed, <span class="type">float</span> tpf) {
  283. <span class="keyword">if</span> (name.equals(<span class="string"><span class="delimiter">&quot;</span><span class="content">shoot</span><span class="delimiter">&quot;</span></span>) &amp;&amp; !keyPressed) {
  284. makeCannonBall();
  285. }
  286. }
  287. };</code></pre></div></div>
  288. <div class="paragraph"><p>In the moment the cannonball appears in the scene, it flies off with the velocity (and in the direction) that you specified using <code>setLinearVelocity()</code> inside <code>makeCannonBall()</code>. The newly created cannon ball flies off, hits the wall, and exerts a <em>physical force</em> that impacts individual bricks.</p></div></div></div>
  289. <div class="sect1"><h2 id="moving-a-physical-spatial">Moving a Physical Spatial</h2><div class="sectionbody"><div class="paragraph"><p>The location of the dynamic Spatial is controlled by its RigidBodyControl. Move the RigidBodyControl to move the Spatial. If it&#8217;s a dynamic PhysicsControl, you can use setLinearVelocity() and apply forces and torques to it. Other RigidBodyControl&#8217;led objects can push the dynamic Spatial around (like pool/billiard balls).</p></div>
  290. <div class="paragraph"><p>You can make Spatials that are not dynamic: Switch the RigidBodyControl to setKinematic(true) to have it move along with its Spatial.</p></div>
  291. <div class="ulist"><ul><li><p>A kinematic is unaffected by forces or gravity, which means it can float in mid-air and cannot be pushed away by dynamic “cannon balls etc.</p></li><li><p>A kinematic RigidBody has a mass.</p></li><li><p>A kinematic can be moved and can exert forces on dynamic RigidBodys. This means you can use a kinematic node as a billiard cue or a remote-controlled battering ram.</p></li></ul></div>
  292. <div class="paragraph"><p>Learn more about static versus kinematic versus dynamic in the <a href="../../jme3/advanced/physics.html">advanced physics doc</a>.</p></div></div></div>
  293. <div class="sect2"><h3 id="excercises">Excercises</h3><div class="sect2"><h3 id="exercise-1-debug-shapes">Exercise 1: Debug Shapes</h3><div class="paragraph"><p>Add the following line after the bulletAppState initialization.</p></div>
  294. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// For older versions up to JME sdk 3.0.10</span>
  295. bulletAppState.getPhysicsSpace().enableDebug(assetManager);</code></pre></div></div>
  296. <div class="paragraph"><p>or</p></div>
  297. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="comment">// For new versions thereafter</span>
  298. bulletAppState.setDebugEnabled(<span class="predefined-constant">true</span>);</code></pre></div></div>
  299. <div class="paragraph"><p>Now you see the collisionShapes of the bricks and spheres, and the floor highlighted.</p></div></div>
  300. <div class="sect2"><h3 id="exercise-2-no-mo-static">Exercise 2: No Mo' Static</h3><div class="paragraph"><p>What happens if you give a static node, such as the floor, a mass of more than 0.0f?</p></div></div>
  301. <div class="sect2"><h3 id="exercise-3-behind-the-curtain">Exercise 3: Behind the Curtain</h3><div class="paragraph"><p>Fill your scene with walls, bricks, and cannon balls. When do you begin to see a performance impact?</p></div>
  302. <div class="paragraph"><p>Popular AAA games use a clever mix of physics, animation and prerendered graphics to give you the illusion of a real, “physical world. Think of your favorite video games and try to spot where and how the game designers trick you into believing that the whole scene is physical. For example, think of a building “breaking into 4-8 parts after an explosion. The pieces most likely fly on predefined (so called kinematic) paths and are only replaced by dynamic Spatials after they touch the ground… Now that you start to implement game physics yourself, look behind the curtain!</p></div>
  303. <div class="paragraph"><p>Using physics everywhere in a game sounds like a cool idea, but it is easily overused. Although the physics nodes are put to “sleep when they are not moving, creating a world solely out of dynamic physics nodes will quickly bring you to the limits of your computer&#8217;s capabilities.</p></div></div></div>
  304. <div class="sect1"><h2 id="conclusion">Conclusion</h2><div class="sectionbody"><div class="paragraph"><p>You have learned how to activate the jBullet PhysicsSpace in an application by adding a <code>BulletAppState</code>. You have created PhysicsControls for simple Shape-based Geometries (for more complex shapes, read up on <a href="../../jme3/advanced/physics.html">CollisionShapes</a>). You have learned that physical objects are not only attached to the rootNode, but also registered to the PhysicsSpace. You know that it makes a difference whether a physical object has a mass (dynamic) or not (static). You are aware that overusing physics has a huge performance impact.</p></div>
  305. <div class="admonitionblock tip"><table><tr><td class="icon"><i class="fa icon-tip" title="Tip"></i></td><td class="content"><div class="paragraph"><p>Congratulations! – You have completed the last beginner tutorial. Now you are ready to start <a href="../../jme3.html">combining what you have learned</a>, to create a cool 3D game of your own. Show us what you can do, and feel free to share your demos, game videos, and screenshots on the <a href="http://hub.jmonkeyengine.org/c/user-code-projects">User Code &amp; Projects Forum</a>!</p></div></td></tr></table></div></div></div></div><div id="footer"><div id="footer-text">Version <br>Last updated 2020-04-29 14:53:30 +00:00</div></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script><script>docsearch({
  306. apiKey: 'a736b6d93de805e26ec2f49b55013fbd',
  307. indexName: 'jmonkeyengine',
  308. inputSelector: '#doc-search',
  309. debug: false // Set debug to true if you want to inspect the dropdown
  310. });</script></body></html>