{"id":1041,"date":"2017-09-18T13:00:29","date_gmt":"2017-09-18T13:00:29","guid":{"rendered":"https:\/\/www.sickgamedev.win\/2017\/09\/18\/creating-a-simple-3d-physics-game-using-three-js-and-physijs\/"},"modified":"2017-09-18T13:00:29","modified_gmt":"2017-09-18T13:00:29","slug":"creating-a-simple-3d-physics-game-using-three-js-and-physijs","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2017\/09\/18\/creating-a-simple-3d-physics-game-using-three-js-and-physijs\/","title":{"rendered":"Creating a Simple 3D Physics Game Using Three.js and Physijs"},"content":{"rendered":"<figure class=\"final-product final-product--image\"><img decoding=\"async\" src=\"https:\/\/cms-assets.tutsplus.com\/uploads\/users\/1605\/posts\/29453\/final_image\/fullgame-physi.png\" alt=\"Final product image\"><figcaption>What You&#8217;ll Be Creating<\/figcaption><\/figure>\n<p>In this tutorial, you&#8217;ll learn how to use Physi.js to add game physics to a 3D scene created using Three.js. We&#8217;ll create a simple game in which we drive a cart around collecting items, using\u00a0basic physics shapes and physics constraints.<\/p>\n<p>This tutorial will be building on top of the concepts shared in my <a href=\"http:\/\/gamedevelopment.tutsplus.com\/tutorials\/creating-a-simple-3d-endless-runner-game-using-three-js--cms-29157\" target=\"_self\">previous Three.js tutorial<\/a>. I would request you to read it if you are new to Three.js and to its 3D scene creation.\u00a0<\/p>\n<p>Due to a technical limitation in hosting web worker based solutions on JSFiddle, we are unable to embed the interactive game in this tutorial page. Please use the provided source code to check out the working example on any cloud-based IDEs or by self-hosting.<\/p>\n<h2>\n<span class=\"sectionnum\">1.<\/span>\u00a03D Physics on the Web<\/h2>\n<p>There are multiple frameworks and engines currently available which can be used to create 3D content for the web with physics. Some of those worth mentioning are <a href=\"http:\/\/biz.turbulenz.com\/developers\" rel=\"external\" target=\"_blank\">Turbulenz<\/a>, <a href=\"http:\/\/www.babylonjs.com\/\" rel=\"external\" target=\"_blank\">BabylonJS<\/a>, <a href=\"https:\/\/playcanvas.com\/\" rel=\"external\" target=\"_blank\">PlayCanvas<\/a>, and the obvious <a href=\"https:\/\/docs.unity3d.com\/Manual\/webgl-building.html\" rel=\"external\" target=\"_blank\">Unity WebGL build<\/a>. But when it comes to popularity and ease of use, most people like to use <a href=\"https:\/\/threejs.org\/\" rel=\"external\" target=\"_blank\">Three.js<\/a> for their experiments. As Three.js is a rendering engine and does not have integrated physics, we need to explore additional frameworks to add the physics capability.<\/p>\n<p>A very popular JavaScript physics solution is <a href=\"https:\/\/github.com\/kripken\/ammo.js\/\" rel=\"external\" target=\"_blank\">Ammo.js<\/a>, which is a direct port of Bullet physics. While directly using Ammo.js is possible, it is not very beginner friendly and has a lot of boilerplate code for each aspect. Also, as it is not manually written but ported using Emscripten, the code is not easy to understand.\u00a0<\/p>\n<p>An alternative solution is to use <a href=\"http:\/\/www.cannonjs.org\/\" rel=\"external\" target=\"_blank\">Cannon.js<\/a> or <a href=\"http:\/\/chandlerprall.github.io\/Physijs\/\" rel=\"external\" target=\"_blank\">Physijs<\/a>. The interesting thing with Physijs is that the focus is always on making things easier, which makes it the ideal choice for beginners. It is built based on Ammo.js and even has a Cannon.js branch. This tutorial uses Physijs and Three.js to build a working game prototype with physics capabilities.\u00a0<\/p>\n<p>Yet another option, although oversimplified, would be to use the\u00a0<a href=\"https:\/\/whsjs.io\/\" rel=\"external\" target=\"_blank\">Whitestorm<\/a> framework, which is a component-based framework based on Three.js and Physijs.\u00a0<\/p>\n<h2>\n<span class=\"sectionnum\">2.<\/span>\u00a0Setting Up Physijs<\/h2>\n<p>We need to have the ammo.js, physi.js, physijs_worker.js and three.js files within our folder structure or coding environment to use Physijs. Physijs uses a web worker to use different threads for physics calculations. So the first step in the integration process is to set up the web worker as below.<\/p>\n<pre class=\"brush: javascript noskimlinks noskimwords\">Physijs.scripts.worker = 'lib\/physijs_worker.js';\nPhysijs.scripts.ammo = 'ammo.js';<\/pre>\n<p>At this point, the setup is complete, and we can start using the physics framework. Physijs has made sure that it followed the coding style of Three.js, and most of the concepts are simple replacements of the corresponding Three.js concept.<\/p>\n<h3>Basic Steps<br \/>\n<\/h3>\n<p>Instead of <code class=\"inline\">THREE.Scene<\/code>, we need to use <code class=\"inline\">Physijs.Scene<\/code>.<\/p>\n<p>There are multiple meshes available in Physijs which need to be used in place of <code class=\"inline\">THREE.Mesh<\/code>. The available options are <code class=\"inline\">PlaneMesh<\/code>, <code class=\"inline\">BoxMesh<\/code>, <code class=\"inline\">SphereMesh<\/code>, <code class=\"inline\">CylinderMesh<\/code>, <code class=\"inline\">ConeMesh<\/code>, <code class=\"inline\">CapsuleMesh<\/code>, <code class=\"inline\">ConvexMesh<\/code>, <code class=\"inline\">ConcaveMesh<\/code>, and <code class=\"inline\">HeighfieldMesh<\/code>.<\/p>\n<p>We need to call the <code class=\"inline\">scene.simulate<\/code> method to do the physics calculations either in the <code class=\"inline\">render<\/code> method or within frequent intervals. Let me remind you that the physics calculations happen in a different thread and will not be in sync or as fast as the scene render loop.\u00a0<\/p>\n<p>Even the next call to <code class=\"inline\">scene.simulate<\/code> may happen while the previous calculations are still running. In order to make it properly in sync with the physics calculations, we could use the Physijs scene&#8217;s\u00a0<code class=\"inline\">update<\/code> event.<\/p>\n<pre class=\"brush: javascript noskimlinks noskimwords\">scene.addEventListener( 'update', function() { \/\/your code. physics calculations have done updating\n});<\/pre>\n<p>In order to register a collision on a Physijs mesh object named arbitrarily as <code class=\"inline\">cube<\/code>, we can listen to the <code class=\"inline\">collision<\/code> event.<\/p>\n<pre class=\"brush: javascript noskimlinks noskimwords\">cube.addEventListener( 'collision', function( objCollidedWith, linearVelOfCollision, angularVelOfCollision ) {\n});<\/pre>\n<p>Within the above method,\u00a0<code class=\"inline\">this<\/code> will refer to <code class=\"inline\">cube<\/code>, while <code class=\"inline\">objCollidedWith<\/code> is the object <code class=\"inline\">cube<\/code> has collided with.<\/p>\n<h2>\n<span class=\"sectionnum\">3.<\/span>\u00a0Example Game Prototype<\/h2>\n<p>For this tutorial, we will be creating a very simple physics-based game where we will use physics constraints to create a vehicle. The player can use arrow keys to drive the vehicle and collect a bouncing ball which randomly appears in the play area.\u00a0<\/p>\n<p>Interestingly, Physijs already has a special <code class=\"inline\">vehicle<\/code> feature which can be directly used for creating vehicles, but we won&#8217;t be using it.<\/p>\n<h3>The Game World<br \/>\n<\/h3>\n<p>Our game world is a vast ground with walls on its four sides as below.<\/p>\n<figure class=\"post_image\"><img decoding=\"async\" alt=\"ground with walls\" src=\"https:\/\/cms-assets.tutsplus.com\/uploads\/users\/1605\/posts\/29453\/image\/physi-game-world.png\"><\/figure>\n<p>We use <code class=\"inline\">Physijs.BoxMesh<\/code> for the ground and the four walls as shown in the code below.<\/p>\n<pre class=\"brush: javascript noskimlinks noskimwords\">ground_material = Physijs.createMaterial( new THREE.MeshStandardMaterial( { color: 0x00ff00 } ),friction, .9 \/\/ low restitution\n);\n\/\/ Ground\nground = new Physijs.BoxMesh(new THREE.BoxGeometry(150, 1, 150),ground_material,0 \/\/ mass\n);\nground.receiveShadow = true;\nscene.add( ground );<\/pre>\n<p>Notice the usage of <code class=\"inline\">Physijs.createMaterial<\/code> to create the necessary physics materials by passing a friction value and a restitution value. The friction value determines the grip on the ground, and the restitution value determines the bounciness. One important thing to note is that when we provide a mass value of <code class=\"inline\">0<\/code>, we create a stationary mesh object.<\/p>\n<h3>The Vehicle<br \/>\n<\/h3>\n<p>We are going to create a special vehicle which has two connected parts. The front part, which has three wheels, acts as the engine, and the rear part, having two wheels, will act as a carriage. The carriage part is connected to the engine part using a hinge joint implemented using a <code class=\"inline\">Physijs.HingeContraint<\/code>.\u00a0<\/p>\n<p>The wheels use <code class=\"inline\">Physijs.DOFConstraint<\/code>, which is a degree of freedom constraint to be attached to the vehicle&#8217;s body while retaining the ability to rotate independently. I would invite you to read the <a href=\"https:\/\/github.com\/chandlerprall\/Physijs\/wiki\/Constraints\" rel=\"external\" target=\"_blank\">official documentation on the various constraints<\/a> available in Physijs.<\/p>\n<p>The engine body and carriage body are simple <code class=\"inline\">BoxMesh<\/code> objects like the <code class=\"inline\">ground<\/code> shown above, but with a definite mass value. They are connected to each other using a hinge joint, as shown in the following code. A hinge joint restricts the motion of the connected object like that of a normal door.<\/p>\n<pre class=\"brush: javascript noskimlinks noskimwords\">car.carriage_constraint = new Physijs.HingeConstraint( car.carriage, \/\/ First object to be constrained car.body, \/\/ constrained to this new THREE.Vector3( 6, 0, 0 ), \/\/ at this point new THREE.Vector3( 0, 1, 0 ) \/\/ along this axis\n);\nscene.addConstraint( car.carriage_constraint );\ncar.carriage_constraint.setLimits( -Math.PI \/ 3, \/\/ minimum angle of motion, in radians Math.PI \/ 3, \/\/ maximum angle of motion, in radians 0, \/\/ applied as a factor to constraint error 0 \/\/ controls bounce at limit (0.0 == no bounce)\n);<\/pre>\n<p>The second part of the code applies limits to the rotation of the hinge, which in this case is between <code class=\"inline\">-Math.PI\/3<\/code> and\u00a0<code class=\"inline\">Math.PI\/3<\/code>.\u00a0<\/p>\n<p>The wheels use a degree of freedom constraint which can be used to set limits on both linear motion and angular motion in all three axes. A method <code class=\"inline\">addWheel<\/code> is created for adding wheels, which takes in multiple parameters.\u00a0<\/p>\n<p>The parameters are the position of the wheel, the weight of the wheel, whether the wheel is big or small, and the wheel reference object. The method returns a newly created <code class=\"inline\">DOFConstraint<\/code>, which is used for driving the vehicle.<\/p>\n<pre class=\"brush: javascript noskimlinks noskimwords\">function addWheel(wheel, pos, isBig, weight){ var geometry=wheel_geometry; if(isBig){ geometry=big_wheel_geometry; } wheel = new Physijs.CylinderMesh( geometry, wheel_material, weight ); wheel.name=\"cart\"; wheel.rotation.x = Math.PI \/ 2; wheel.position.set(pos.x,pos.y,pos.z); wheel.castShadow = true; scene.add( wheel ); wheel.setDamping(0,damping); var wheelConstraint = new Physijs.DOFConstraint( wheel, car.body, pos ); if(isBig){ wheelConstraint = new Physijs.DOFConstraint( wheel, car.carriage, pos); } scene.addConstraint( wheelConstraint ); wheelConstraint.setAngularLowerLimit({ x: 0, y: 0, z: 0 }); wheelConstraint.setAngularUpperLimit({ x: 0, y: 0, z: 0 }); return wheelConstraint;\n}<\/pre>\n<p>The big wheels need to be attached to the carriage, and the small wheels are attached to the engine. The wheels are given a damping value so that their angular velocity gets reduced when no external force is being applied. This makes sure that the vehicle slows down when we release the accelerator.\u00a0<\/p>\n<p>We will explore the driving logic in a later section. Each wheel mesh along with the car meshes are assigned the name of <code class=\"inline\">cart<\/code> for identification purposes during the collision call back. Each wheel constraint has different angular limits, which are set independently once they are created. For example, here is the code for the front middle wheel of the engine, <code class=\"inline\">car.wheel_fm<\/code>, and the corresponding constraint,\u00a0<code class=\"inline\">car.wheel_fm_constraint<\/code>.<\/p>\n<pre class=\"brush: javascript noskimlinks noskimwords\">car.wheel_fm_constraint=addWheel(car.wheel_fm, new THREE.Vector3( -7.5, 6.5, 0 ),false,300);\ncar.wheel_fm_constraint.setAngularLowerLimit({ x: 0, y: -Math.PI \/ 8, z: 1 });\ncar.wheel_fm_constraint.setAngularUpperLimit({ x: 0, y: Math.PI \/ 8, z: 0 });<\/pre>\n<h3>The Ball<\/h3>\n<p>The ball is a\u00a0<code class=\"inline\">Physijs.SphereMesh<\/code> object with a lower mass value of <code class=\"inline\">20<\/code>. We use the <code class=\"inline\">releaseBall<\/code> method to position the ball randomly within our game area whenever it gets collected.\u00a0<\/p>\n<pre class=\"brush: javascript noskimlinks noskimwords\">function addBall(){ var ball_material = Physijs.createMaterial(new THREE.MeshStandardMaterial({ color: 0x0000ff ,shading:THREE.FlatShading}),friction,.9 \/\/ good restitution ); var ball_geometry = new THREE.SphereGeometry( 2,16,16); ball = new Physijs.SphereMesh(ball_geometry,ball_material,20); ball.castShadow = true; releaseBall(); scene.add( ball ); ball.setDamping(0,0.9); ball.addEventListener( 'collision', onCollision);\n}\nfunction releaseBall(){ var range =10+Math.random()*30; ball.position.y = 16; ball.position.x = ((2*Math.floor(Math.random()*2))-1)*range; ball.position.z = ((2*Math.floor(Math.random()*2))-1)*range; ball.__dirtyPosition = true;\/\/force new position \/\/ You also need to cancel the object's velocity ball.setLinearVelocity(new THREE.Vector3(0, 0, 0)); ball.setAngularVelocity(new THREE.Vector3(0, 0, 0));\n}<\/pre>\n<p>One thing worth noticing is the fact that we need to <a href=\"https:\/\/github.com\/chandlerprall\/Physijs\/wiki\/Updating-an-object's-position-&amp;-rotation\" rel=\"external\" target=\"_blank\">override the position values set by the physics simulation in order to reposition<\/a> our ball. For this, we use the <code class=\"inline\">__dirtyPosition<\/code> flag, which makes sure that the new position is used for further physics simulation.<\/p>\n<p>The ball gets collected when it collides with any part of the vehicle which happens in the <code class=\"inline\">onCollision<\/code> listener method.<\/p>\n<pre class=\"brush: javascript noskimlinks noskimwords\">function onCollision(other_object, linear_velocity, angular_velocity ){ if(other_object.name===\"cart\"){ score++; releaseBall(); scoreText.innerHTML=score.toString(); }\n}<\/pre>\n<h3>Driving the Vehicle<\/h3>\n<p>We add event listeners for the <code class=\"inline\">onkeydown<\/code> and <code class=\"inline\">onkeyup<\/code> events of the document, where we determine the <code class=\"inline\">keyCode<\/code> to set the values of the corresponding wheel constraints. The theory is that the single front wheel of the engine controls the turning of our vehicle, and the two wheels on the rear of the engine control the acceleration and deceleration. The wheels on the carriage do not play any part in the driving.<\/p>\n<pre class=\"brush: javascript noskimlinks noskimwords\">document.onkeydown = handleKeyDown;\ndocument.onkeyup = handleKeyUp; function handleKeyDown(keyEvent){ switch( keyEvent.keyCode ) { case 37: \/\/ Left car.wheel_fm_constraint.configureAngularMotor( 1, -Math.PI \/ 3, Math.PI \/ 3, 1, 200 ); car.wheel_fm_constraint.enableAngularMotor( 1 ); break; case 39: \/\/ Right car.wheel_fm_constraint.configureAngularMotor( 1, -Math.PI \/ 3, Math.PI \/ 3, -1, 200 ); car.wheel_fm_constraint.enableAngularMotor( 1 ); break; case 38: \/\/ Up car.wheel_bl_constraint.configureAngularMotor( 2, 1, 0, 6, 2000 ); car.wheel_br_constraint.configureAngularMotor( 2, 1, 0, 6, 2000 ); car.wheel_bl_constraint.enableAngularMotor( 2 ); car.wheel_br_constraint.enableAngularMotor( 2 ); break; case 40: \/\/ Down car.wheel_bl_constraint.configureAngularMotor( 2, 1, 0, -6, 2000 ); car.wheel_br_constraint.configureAngularMotor( 2, 1, 0, -6, 2000 ); car.wheel_bl_constraint.enableAngularMotor( 2 ); car.wheel_br_constraint.enableAngularMotor( 2 ); break; }\n}\nfunction handleKeyUp(keyEvent){ switch( keyEvent.keyCode ) { case 37: \/\/ Left car.wheel_fm_constraint.disableAngularMotor( 1 ); break; case 39: \/\/ Right car.wheel_fm_constraint.disableAngularMotor( 1 ); break; case 38: \/\/ Up car.wheel_bl_constraint.disableAngularMotor( 2 ); car.wheel_br_constraint.disableAngularMotor( 2 ); break; case 40: \/\/ Down car.wheel_bl_constraint.disableAngularMotor( 2 ); car.wheel_br_constraint.disableAngularMotor( 2 ); break; }\n}<\/pre>\n<p>The <code class=\"inline\">DOFConstraint<\/code> uses the <code class=\"inline\">enableAngularMotor<\/code> method to apply angular velocity on the wheel which turns the wheel based on the axis value provided as a parameter. Basically, we only turn the wheels, and the motion of the vehicle happens due to the frictional response of the ground, as in the real world.<\/p>\n<figure class=\"post_image\"><img decoding=\"async\" alt=\"the completed game\" src=\"https:\/\/cms-assets.tutsplus.com\/uploads\/users\/1605\/posts\/29453\/image\/fullgame-physi.png\"><\/figure>\n<p>We are unable to embed the working game in this page as mentioned at the start of the tutorial. Please go through the complete source to understand how everything is wired together.<\/p>\n<h2>Conclusion<\/h2>\n<p>This is a very simple introduction to implementing physics in your Three.js 3D world. The Physijs documentation is sorely lacking, but there are many <a href=\"https:\/\/github.com\/chandlerprall\/Physijs\/tree\/master\/examples\" rel=\"external\" target=\"_blank\">examples<\/a> already available which are worth looking into. Physijs is a very beginner-friendly framework, like Three.js, when you consider the complexity that is present under the hood.\u00a0<\/p>\n<p>JavaScript is clearly popular for game development as well as web development. It\u2019s not without its learning curves, and there are plenty of frameworks and libraries to keep you busy, as well. If you\u2019re looking for additional resources to study or to use in your work, check out what we have available in the <a href=\"https:\/\/codecanyon.net\/category\/javascript\">Envato marketplace<\/a>.<\/p>\n<p>Hope this tutorial helps you get started in exploring the interesting world of 3D web game physics.<\/p>\n<div class=\"mediafed_ad\"><img loading=\"lazy\" decoding=\"async\" border=\"0\" height=\"1\" src=\"https:\/\/www.sickgamedev.win\/wp-content\/uploads\/2017\/10\/creating-a-simple-3d-physics-game-using-three-js-and-physijs.gif\" width=\"1\" \/><a href=\"http:\/\/da.feedsportal.com\/r\/186529796139\/u\/407\/f\/668810\/c\/35227\/s\/29453\/a2.htm\"><img decoding=\"async\" border=\"0\" src=\"https:\/\/www.sickgamedev.win\/wp-content\/uploads\/2017\/10\/creating-a-simple-3d-physics-game-using-three-js-and-physijs.img\" \/><\/a><img loading=\"lazy\" decoding=\"async\" border=\"0\" height=\"1\" src=\"https:\/\/www.sickgamedev.win\/wp-content\/uploads\/2017\/10\/creating-a-simple-3d-physics-game-using-three-js-and-physijs-2.img\" width=\"1\" \/><\/div>\n","protected":false},"excerpt":{"rendered":"<p>What You&#8217;ll Be Creating In this tutorial, you&#8217;ll learn how to use Physi.js to add game physics to a 3D scene created using Three.js. We&#8217;ll create a simple game in which we drive a cart around collecting items, using\u00a0basic physics shapes and physics constraints. This tutorial will be building on top of the concepts shared [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1042,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-1041","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/1041","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=1041"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/1041\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media\/1042"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=1041"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=1041"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=1041"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}