terrain_collision.html 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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="terrain, collision"><title>terrain_collision</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/advanced/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/advanced/terrain_collision.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/advanced/"><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>terrain_collision</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="#terrain-collision">Terrain Collision</a></li><li><a href="#sample-code">Sample Code</a></li><li><a href="#understanding-the-code">Understanding the Code</a><ul class="sectlevel2"><li><a href="#the-terrain-code">The Terrain Code</a></li><li><a href="#the-collision-detection-code">The Collision Detection Code</a></li><li><a href="#combining-the-two">Combining the Two</a></li></ul></li><li><a href="#conclusion">Conclusion</a></li></ul></div></div><div id="content"><div class="sect1"><h2 id="terrain-collision">Terrain Collision</h2><div class="sectionbody"><div class="paragraph"><p>This tutorial expands the HelloTerrain tutorial and makes the terrain solid. You combine what you learned in <a href="../../jme3/beginner/hello_terrain.html">Hello Terrain</a> and <a href="../../jme3/beginner/hello_collision.html">Hello Collision</a> and add a CollisionShape to the terrain. The terrain&#8217;s CollisionShape lets the first-person player (who is also a CollisionShape) collide with the terrain, i.e. walk on it and stand on it.</p></div></div></div>
  4. <div class="sect1"><h2 id="sample-code">Sample Code</h2><div class="sectionbody"><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>;
  5. <span class="keyword">import</span> <span class="include">com.jme3.app.SimpleApplication</span>;
  6. <span class="keyword">import</span> <span class="include">com.jme3.bullet.BulletAppState</span>;
  7. <span class="keyword">import</span> <span class="include">com.jme3.bullet.collision.shapes.CapsuleCollisionShape</span>;
  8. <span class="keyword">import</span> <span class="include">com.jme3.bullet.collision.shapes.CollisionShape</span>;
  9. <span class="keyword">import</span> <span class="include">com.jme3.bullet.control.CharacterControl</span>;
  10. <span class="keyword">import</span> <span class="include">com.jme3.bullet.control.RigidBodyControl</span>;
  11. <span class="keyword">import</span> <span class="include">com.jme3.bullet.util.CollisionShapeFactory</span>;
  12. <span class="keyword">import</span> <span class="include">com.jme3.input.KeyInput</span>;
  13. <span class="keyword">import</span> <span class="include">com.jme3.input.controls.ActionListener</span>;
  14. <span class="keyword">import</span> <span class="include">com.jme3.input.controls.KeyTrigger</span>;
  15. <span class="keyword">import</span> <span class="include">com.jme3.material.Material</span>;
  16. <span class="keyword">import</span> <span class="include">com.jme3.math.Vector3f</span>;
  17. <span class="keyword">import</span> <span class="include">com.jme3.renderer.Camera</span>;
  18. <span class="keyword">import</span> <span class="include">com.jme3.scene.Node</span>;
  19. <span class="keyword">import</span> <span class="include">com.jme3.terrain.geomipmap.TerrainLodControl</span>;
  20. <span class="keyword">import</span> <span class="include">com.jme3.terrain.heightmap.AbstractHeightMap</span>;
  21. <span class="keyword">import</span> <span class="include">com.jme3.terrain.geomipmap.TerrainQuad</span>;
  22. <span class="keyword">import</span> <span class="include">com.jme3.terrain.heightmap.ImageBasedHeightMap</span>;
  23. <span class="keyword">import</span> <span class="include">com.jme3.texture.Texture</span>;
  24. <span class="keyword">import</span> <span class="include">com.jme3.texture.Texture.WrapMode</span>;
  25. <span class="keyword">import</span> <span class="include">java.util.ArrayList</span>;
  26. <span class="keyword">import</span> <span class="include">java.util.List</span>;
  27. <span class="keyword">import</span> <span class="include">jme3tools.converters.ImageToAwt</span>;
  28. <span class="comment">/**
  29. * This demo shows a terrain with collision detection,
  30. * that you can walk around in with a first-person perspective.
  31. * This code combines HelloCollision and HelloTerrain.
  32. */</span>
  33. <span class="directive">public</span> <span class="type">class</span> <span class="class">HelloTerrainCollision</span> <span class="directive">extends</span> SimpleApplication
  34. <span class="directive">implements</span> <span class="predefined-type">ActionListener</span> {
  35. <span class="directive">private</span> BulletAppState bulletAppState;
  36. <span class="directive">private</span> RigidBodyControl landscape;
  37. <span class="directive">private</span> CharacterControl player;
  38. <span class="directive">private</span> Vector3f walkDirection = <span class="keyword">new</span> Vector3f();
  39. <span class="directive">private</span> <span class="type">boolean</span> left = <span class="predefined-constant">false</span>, right = <span class="predefined-constant">false</span>, up = <span class="predefined-constant">false</span>, down = <span class="predefined-constant">false</span>;
  40. <span class="directive">private</span> TerrainQuad terrain;
  41. <span class="directive">private</span> Material mat_terrain;
  42. <span class="directive">public</span> <span class="directive">static</span> <span class="type">void</span> main(<span class="predefined-type">String</span><span class="type">[]</span> args) {
  43. HelloTerrainCollision app = <span class="keyword">new</span> HelloTerrainCollision();
  44. app.start();
  45. }
  46. <span class="annotation">@Override</span>
  47. <span class="directive">public</span> <span class="type">void</span> simpleInitApp() {
  48. <span class="comment">/** Set up Physics */</span>
  49. bulletAppState = <span class="keyword">new</span> BulletAppState();
  50. stateManager.attach(bulletAppState);
  51. <span class="comment">//Uncomment for debugging.</span>
  52. <span class="error"> </span> <span class="comment">//bulletAppState.setDebugEnabled(true);</span>
  53. flyCam.setMoveSpeed(<span class="integer">100</span>);
  54. setUpKeys();
  55. <span class="comment">/** 1. Create terrain material and load four textures into it. */</span>
  56. mat_terrain = <span class="keyword">new</span> Material(assetManager,
  57. <span class="string"><span class="delimiter">&quot;</span><span class="content">Common/MatDefs/Terrain/Terrain.j3md</span><span class="delimiter">&quot;</span></span>);
  58. <span class="comment">/** 1.1) Add ALPHA map (for red-blue-green coded splat textures) */</span>
  59. mat_terrain.setTexture(<span class="string"><span class="delimiter">&quot;</span><span class="content">Alpha</span><span class="delimiter">&quot;</span></span>, assetManager.loadTexture(
  60. <span class="string"><span class="delimiter">&quot;</span><span class="content">Textures/Terrain/splat/alphamap.png</span><span class="delimiter">&quot;</span></span>));
  61. <span class="comment">/** 1.2) Add GRASS texture into the red layer (Tex1). */</span>
  62. Texture grass = assetManager.loadTexture(
  63. <span class="string"><span class="delimiter">&quot;</span><span class="content">Textures/Terrain/splat/grass.jpg</span><span class="delimiter">&quot;</span></span>);
  64. grass.setWrap(WrapMode.Repeat);
  65. mat_terrain.setTexture(<span class="string"><span class="delimiter">&quot;</span><span class="content">Tex1</span><span class="delimiter">&quot;</span></span>, grass);
  66. mat_terrain.setFloat(<span class="string"><span class="delimiter">&quot;</span><span class="content">Tex1Scale</span><span class="delimiter">&quot;</span></span>, <span class="float">64f</span>);
  67. <span class="comment">/** 1.3) Add DIRT texture into the green layer (Tex2) */</span>
  68. Texture dirt = assetManager.loadTexture(
  69. <span class="string"><span class="delimiter">&quot;</span><span class="content">Textures/Terrain/splat/dirt.jpg</span><span class="delimiter">&quot;</span></span>);
  70. dirt.setWrap(WrapMode.Repeat);
  71. mat_terrain.setTexture(<span class="string"><span class="delimiter">&quot;</span><span class="content">Tex2</span><span class="delimiter">&quot;</span></span>, dirt);
  72. mat_terrain.setFloat(<span class="string"><span class="delimiter">&quot;</span><span class="content">Tex2Scale</span><span class="delimiter">&quot;</span></span>, <span class="float">32f</span>);
  73. <span class="comment">/** 1.4) Add ROAD texture into the blue layer (Tex3) */</span>
  74. Texture rock = assetManager.loadTexture(
  75. <span class="string"><span class="delimiter">&quot;</span><span class="content">Textures/Terrain/splat/road.jpg</span><span class="delimiter">&quot;</span></span>);
  76. rock.setWrap(WrapMode.Repeat);
  77. mat_terrain.setTexture(<span class="string"><span class="delimiter">&quot;</span><span class="content">Tex3</span><span class="delimiter">&quot;</span></span>, rock);
  78. mat_terrain.setFloat(<span class="string"><span class="delimiter">&quot;</span><span class="content">Tex3Scale</span><span class="delimiter">&quot;</span></span>, <span class="float">128f</span>);
  79. <span class="comment">/** 2. Create the height map */</span>
  80. AbstractHeightMap heightmap = <span class="predefined-constant">null</span>;
  81. Texture heightMapImage = assetManager.loadTexture(
  82. <span class="string"><span class="delimiter">&quot;</span><span class="content">Textures/Terrain/splat/mountains512.png</span><span class="delimiter">&quot;</span></span>);
  83. heightmap = <span class="keyword">new</span> ImageBasedHeightMap(heightMapImage.getImage());
  84. heightmap.load();
  85. <span class="comment">/** 3. We have prepared material and heightmap.
  86. * Now we create the actual terrain:
  87. * 3.1) Create a TerrainQuad and name it &quot;my terrain&quot;.
  88. * 3.2) A good value for terrain tiles is 64x64 -- so we supply 64+1=65.
  89. * 3.3) We prepared a heightmap of size 512x512 -- so we supply 512+1=513.
  90. * 3.4) As LOD step scale we supply Vector3f(1,1,1).
  91. * 3.5) We supply the prepared heightmap itself.
  92. */</span>
  93. terrain = <span class="keyword">new</span> TerrainQuad(<span class="string"><span class="delimiter">&quot;</span><span class="content">my terrain</span><span class="delimiter">&quot;</span></span>, <span class="integer">65</span>, <span class="integer">513</span>, heightmap.getHeightMap());
  94. <span class="comment">/** 4. We give the terrain its material, position &amp; scale it, and attach it. */</span>
  95. terrain.setMaterial(mat_terrain);
  96. terrain.setLocalTranslation(<span class="integer">0</span>, -<span class="integer">100</span>, <span class="integer">0</span>);
  97. terrain.setLocalScale(<span class="float">2f</span>, <span class="float">1f</span>, <span class="float">2f</span>);
  98. rootNode.attachChild(terrain);
  99. <span class="comment">/** 5. The LOD (level of detail) depends on were the camera is: */</span>
  100. <span class="predefined-type">List</span>&lt;Camera&gt; cameras = <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;Camera&gt;();
  101. cameras.add(getCamera());
  102. TerrainLodControl control = <span class="keyword">new</span> TerrainLodControl(terrain, cameras);
  103. terrain.addControl(control);
  104. <span class="comment">/** 6. Add physics: */</span>
  105. <span class="comment">// We set up collision detection for the scene by creating a static</span>
  106. RigidBodyControl with mass zero.*/
  107. terrain.addControl(<span class="keyword">new</span> RigidBodyControl(<span class="integer">0</span>));
  108. <span class="comment">/**
  109. * We set up collision detection for the player by creating
  110. * a capsule collision shape and a CharacterControl.
  111. * The CharacterControl offers extra settings for
  112. * size, stepheight, jumping, falling, and gravity.
  113. * We also put the player in its starting position.
  114. */</span>
  115. CapsuleCollisionShape capsuleShape = <span class="keyword">new</span> CapsuleCollisionShape(<span class="float">1.5f</span>, <span class="float">6f</span>, <span class="integer">1</span>);
  116. player = <span class="keyword">new</span> CharacterControl(capsuleShape, <span class="float">0.05f</span>);
  117. player.setJumpSpeed(<span class="integer">20</span>);
  118. player.setFallSpeed(<span class="integer">30</span>);
  119. player.setPhysicsLocation(<span class="keyword">new</span> Vector3f(-<span class="integer">10</span>, <span class="integer">10</span>, <span class="integer">10</span>));
  120. <span class="comment">// We attach the scene and the player to the rootnode and the physics space,</span>
  121. <span class="comment">// to make them appear in the game world.</span>
  122. bulletAppState.getPhysicsSpace().add(terrain);
  123. bulletAppState.getPhysicsSpace().add(player);
  124. <span class="comment">// You can change the gravity of individual physics objects after they are</span>
  125. <span class="comment">// added to the PhysicsSpace.</span>
  126. player.setGravity(<span class="keyword">new</span> Vector3f(<span class="integer">0</span>,-<span class="float">30f</span>,<span class="integer">0</span>));
  127. }
  128. <span class="comment">/** We over-write some navigational key mappings here, so we can
  129. * add physics-controlled walking and jumping: */</span>
  130. <span class="directive">private</span> <span class="type">void</span> setUpKeys() {
  131. inputManager.addMapping(<span class="string"><span class="delimiter">&quot;</span><span class="content">Left</span><span class="delimiter">&quot;</span></span>, <span class="keyword">new</span> KeyTrigger(KeyInput.KEY_A));
  132. inputManager.addMapping(<span class="string"><span class="delimiter">&quot;</span><span class="content">Right</span><span class="delimiter">&quot;</span></span>, <span class="keyword">new</span> KeyTrigger(KeyInput.KEY_D));
  133. inputManager.addMapping(<span class="string"><span class="delimiter">&quot;</span><span class="content">Up</span><span class="delimiter">&quot;</span></span>, <span class="keyword">new</span> KeyTrigger(KeyInput.KEY_W));
  134. inputManager.addMapping(<span class="string"><span class="delimiter">&quot;</span><span class="content">Down</span><span class="delimiter">&quot;</span></span>, <span class="keyword">new</span> KeyTrigger(KeyInput.KEY_S));
  135. inputManager.addMapping(<span class="string"><span class="delimiter">&quot;</span><span class="content">Jump</span><span class="delimiter">&quot;</span></span>, <span class="keyword">new</span> KeyTrigger(KeyInput.KEY_SPACE));
  136. inputManager.addListener(<span class="local-variable">this</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">Left</span><span class="delimiter">&quot;</span></span>);
  137. inputManager.addListener(<span class="local-variable">this</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">Right</span><span class="delimiter">&quot;</span></span>);
  138. inputManager.addListener(<span class="local-variable">this</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">Up</span><span class="delimiter">&quot;</span></span>);
  139. inputManager.addListener(<span class="local-variable">this</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">Down</span><span class="delimiter">&quot;</span></span>);
  140. inputManager.addListener(<span class="local-variable">this</span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">Jump</span><span class="delimiter">&quot;</span></span>);
  141. }
  142. <span class="comment">/** These are our custom actions triggered by key presses.
  143. * We do not walk yet, we just keep track of the direction the user pressed. */</span>
  144. <span class="directive">public</span> <span class="type">void</span> onAction(<span class="predefined-type">String</span> binding, <span class="type">boolean</span> value, <span class="type">float</span> tpf) {
  145. <span class="keyword">if</span> (binding.equals(<span class="string"><span class="delimiter">&quot;</span><span class="content">Left</span><span class="delimiter">&quot;</span></span>)) {
  146. <span class="keyword">if</span> (value) { left = <span class="predefined-constant">true</span>; } <span class="keyword">else</span> { left = <span class="predefined-constant">false</span>; }
  147. } <span class="keyword">else</span> <span class="keyword">if</span> (binding.equals(<span class="string"><span class="delimiter">&quot;</span><span class="content">Right</span><span class="delimiter">&quot;</span></span>)) {
  148. <span class="keyword">if</span> (value) { right = <span class="predefined-constant">true</span>; } <span class="keyword">else</span> { right = <span class="predefined-constant">false</span>; }
  149. } <span class="keyword">else</span> <span class="keyword">if</span> (binding.equals(<span class="string"><span class="delimiter">&quot;</span><span class="content">Up</span><span class="delimiter">&quot;</span></span>)) {
  150. <span class="keyword">if</span> (value) { up = <span class="predefined-constant">true</span>; } <span class="keyword">else</span> { up = <span class="predefined-constant">false</span>; }
  151. } <span class="keyword">else</span> <span class="keyword">if</span> (binding.equals(<span class="string"><span class="delimiter">&quot;</span><span class="content">Down</span><span class="delimiter">&quot;</span></span>)) {
  152. <span class="keyword">if</span> (value) { down = <span class="predefined-constant">true</span>; } <span class="keyword">else</span> { down = <span class="predefined-constant">false</span>; }
  153. } <span class="keyword">else</span> <span class="keyword">if</span> (binding.equals(<span class="string"><span class="delimiter">&quot;</span><span class="content">Jump</span><span class="delimiter">&quot;</span></span>)) {
  154. player.jump(<span class="keyword">new</span> Vector3f(<span class="integer">0</span>,<span class="float">20f</span>,<span class="integer">0</span>));
  155. }
  156. }
  157. <span class="comment">/**
  158. * This is the main event loop--walking happens here.
  159. * We check in which direction the player is walking by interpreting
  160. * the camera direction forward (camDir) and to the side (camLeft).
  161. * The setWalkDirection() command is what lets a physics-controlled player walk.
  162. * We also make sure here that the camera moves with player.
  163. */</span>
  164. <span class="annotation">@Override</span>
  165. <span class="directive">public</span> <span class="type">void</span> simpleUpdate(<span class="type">float</span> tpf) {
  166. Vector3f camDir = cam.getDirection().clone().multLocal(<span class="float">0.6f</span>);
  167. Vector3f camLeft = cam.getLeft().clone().multLocal(<span class="float">0.4f</span>);
  168. walkDirection.set(<span class="integer">0</span>, <span class="integer">0</span>, <span class="integer">0</span>);
  169. <span class="keyword">if</span> (left) { walkDirection.addLocal(camLeft); }
  170. <span class="keyword">if</span> (right) { walkDirection.addLocal(camLeft.negate()); }
  171. <span class="keyword">if</span> (up) { walkDirection.addLocal(camDir); }
  172. <span class="keyword">if</span> (down) { walkDirection.addLocal(camDir.negate()); }
  173. player.setWalkDirection(walkDirection);
  174. cam.setLocation(player.getPhysicsLocation());
  175. }
  176. }</code></pre></div></div>
  177. <div class="paragraph"><p>To try this code, create a <code><span class="menuseq"><span class="menu">New Project</span>&#160;&#9656; <span class="submenu">JME3</span>&#160;&#9656; <span class="menuitem">BasicGame</span></span></code> using the default settings. Paste the sample code over the pregenerated Main.java class. Change the package to &#8216;mygame&#8217; if necessary. Open the <code><span class="menuseq"><span class="menu">File</span>&#160;&#9656; <span class="submenu">Project Properties</span>&#160;&#9656; <span class="menuitem">Libraries</span></span></code> and add the <code>jme3-test-data</code> library to make certain you have all the files.</p></div>
  178. <div class="paragraph"><p>Compile and run the code. You should see a terrain. You can use the WASD keys and the mouse to run up and down the hills.</p></div></div></div>
  179. <div class="sect2"><h3 id="understanding-the-code">Understanding the Code</h3><div class="sect2"><h3 id="the-terrain-code">The Terrain Code</h3><div class="paragraph"><p>Read <a href="../../jme3/beginner/hello_terrain.html">Hello Terrain</a> for details of the following parts that we reuse:</p></div>
  180. <div class="olist arabic"><ol class="arabic"><li><p>The <code>AbstractHeightMap</code> is an efficient way to describe the shape of the terrain.</p></li><li><p>The <code>Terrain.j3md</code>-based Material and its texture layers let you colorize rocky mountain, grassy valleys, and a paved path criss-crossing over the landscape.</p></li><li><p>The TerrainQuad is the finished <code>terrain</code> Spatial that you attach to the rootNode.</p></li></ol></div></div>
  181. <div class="sect2"><h3 id="the-collision-detection-code">The Collision Detection Code</h3><div class="paragraph"><p>Read <a href="../../jme3/beginner/hello_collision.html">Hello Collision</a> for details of the following parts that we reuse:</p></div>
  182. <div class="olist arabic"><ol class="arabic"><li><p>The <code>BulletAppState</code> lines activate physics.</p></li><li><p>The <code>ActionListener</code> (<code>onAction()</code>) lets you reconfigure the input handling for the first-person player, so it takes collision detection into account.</p></li><li><p>The custom <code>setUpKeys()</code> method loads your reconfigured input handlers. They now don&#8217;t just walk blindly, but calculate the <code>walkDirection</code> vector that we need for collision detection.</p></li><li><p><code>simpleUpdate()</code> uses the <code>walkDirection</code> vector and makes the character walk, while taking obstacles and solid walls/floor into account.</p></li></ol></div>
  183. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java">player.setWalkDirection(walkDirection);</code></pre></div></div>
  184. <div class="olist arabic"><ol class="arabic"><li><p>The RigidBodyControl <code>landscape</code> is the CollisionShape of the terrain.</p></li><li><p>The physical first-person player is a CapsuleCollisionShape with a CharacterControl.</p></li></ol></div></div>
  185. <div class="sect2"><h3 id="combining-the-two">Combining the Two</h3><div class="paragraph"><p>Here are the changed parts to combine the two:</p></div>
  186. <div class="olist arabic"><ol class="arabic"><li><p>You create a static (zero-mass) RigidBodyControl.</p></li><li><p>Add the control to the <code>terrain</code> to make it physical.</p></li></ol></div>
  187. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="comment">/** 6. Add physics: */</span>
  188. terrain.addControl(<span class="keyword">new</span> RigidBodyControl(<span class="integer">0</span>));</code></pre></div></div>
  189. <div class="paragraph"><p>You attach the <code>terrain</code> and the first-person <code>player</code> to the rootNode, and to the physics space, to make them appear in the game world.</p></div>
  190. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"> bulletAppState.getPhysicsSpace().add(terrain);
  191. bulletAppState.getPhysicsSpace().add(player);</code></pre></div></div></div></div>
  192. <div class="sect1"><h2 id="conclusion">Conclusion</h2><div class="sectionbody"><div class="paragraph"><p>You see that you can combine snippets of sample code (such as HelloTerrain and HelloCollision), and create a new application from it that combines two features into soemthing new.</p></div>
  193. <div class="paragraph"><p>You should spawn high up in the area and fall down to the map, giving you a few seconds to survey the area. Then walk around and see how you like the lay of the land.</p></div>
  194. <hr>
  195. <div class="paragraph"><p>See also:</p></div>
  196. <div class="ulist"><ul><li><p><a href="../../jme3/beginner/hello_terrain.html">Hello Terrain</a>,</p></li><li><p><a href="../../jme3/advanced/terrain.html">Terrain</a></p></li></ul></div></div></div></div><div id="footer"><div id="footer-text">Version <br>Last updated 2019-12-20 23:30:51 +00:00</div></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script><script>docsearch({
  197. apiKey: 'a736b6d93de805e26ec2f49b55013fbd',
  198. indexName: 'jmonkeyengine',
  199. inputSelector: '#doc-search',
  200. debug: false // Set debug to true if you want to inspect the dropdown
  201. });</script></body></html>