// ==== Starter World =================================================================================================// This code is designed for use on the Ancient Brain site.// This code may be freely copied and edited by anyone on the Ancient Brain site.// To include a working run of this program on another site, see the "Embed code" links provided on Ancient Brain.// ====================================================================================================================// Demo of Physijs based World// From here, with many changes:// http://chandlerprall.github.io/Physijs/examples/collisions.html// ===================================================================================================================// === Start of tweaker's box ======================================================================================== // ===================================================================================================================// The easiest things to modify are in this box.// You should be able to change things in this box without being a JavaScript programmer.// Go ahead and change some of these. What's the worst that could happen?
AB.clockTick =100;// Speed of run: Step every n milliseconds. Default 100.
AB.maxSteps =2000;// Length of run: Maximum length of run in steps. Default 1000.
AB.screenshotStep =200;// Take screenshot on this step. (All resources should have finished loading.) Default 50.const BOXSIZE =5;const BOXPOS = BOXSIZE *2;// range of box x,z start positions const BOXHEIGHT = BOXSIZE *10;// y start position of boxes const HEAVYIMPACT =30;// heavy impacts have y velocity greater than this const GROUNDSIZE = BOXSIZE *40;const startRadius = BOXSIZE *15;const maxRadius = BOXSIZE *250;const TEXTURE_FILE_0 ='/uploads/starter/smiley.png';const TEXTURE_FILE_1 ='/uploads/starter/ghost.3.png';// https://commons.wikimedia.org/wiki/Smileyconst TEXTURE_GROUND ='/uploads/starter/rocks.jpg';const SOUND_COLLISION ='/uploads/starter/wooden.mp3';// credit:// http://soundbible.com/715-Dropped-Wooden-Floor.htmlconst SOUND_BEEP ='/uploads/starter/beep.mp3';const SKYCOLOR =0xffffcc;const GROUND_FRICTION =0.8;const GROUND_RESTITUTION =0.3;const BOX_FRICTION =0.6;const BOX_RESTITUTION =0.3;// define gravity along x,y,z dimensions:var gravity =new THREE.Vector3(0,-30,0);// var gravity = new THREE.Vector3 ( -30, -30, 0 );function nextboxin()// Speed of box creation // Create next box in some random (m to n) milliseconds time.{return( AB.randomIntAtoB (2000,4000));// return ( AB.randomIntAtoB ( 200, 1000 ) ); }// ===================================================================================================================// === End of tweaker's box ==========================================================================================// ===================================================================================================================// You will need to be some sort of JavaScript programmer to change things below the tweaker's box.var resourcesLoaded =false;var splashClicked =false;var box_texture_0, box_texture_1 ;var ground_texture ;var boxno =0;var currentbox ;function loadResources()// asynchronous file loads - call initScene() when all finished {var loader1 =new THREE.TextureLoader();var loader2 =new THREE.TextureLoader();var loader3 =new THREE.TextureLoader();
loader1.load ( TEXTURE_GROUND,function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
ground_texture = thetexture;if( asynchFinished()) initScene();// if all file loads have returned });
loader2.load ( TEXTURE_FILE_0,function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
box_texture_0 = thetexture;if( asynchFinished()) initScene();});
loader3.load ( TEXTURE_FILE_1,function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
box_texture_1 = thetexture;if( asynchFinished()) initScene();});}function asynchFinished()// all file loads returned {if( ground_texture && box_texture_0 && box_texture_1 )returntrue;elsereturnfalse;}function initScene()// all file loads have returned {// --- Light ------------------------------------------------------------------var light =new THREE.DirectionalLight(0xFFFFFF,1.3);
light.position.set( BOXHEIGHT,(BOXHEIGHT *2),0);
light.target.position.copy(ABWorld.scene.position );
light.castShadow =true;// how far away to draw shadows:
light.shadow.camera.left =-GROUNDSIZE;
light.shadow.camera.right = GROUNDSIZE;
light.shadow.camera.bottom =-GROUNDSIZE;
light.shadow.camera.top = GROUNDSIZE;
light.shadow.bias =-0.0001;// higher quality shadows at expense of computation time// slower PCs can struggle if this is too high// World author could make it an option at run-time - high or low graphics option - or just shadows on/off
light.shadow.mapSize.width =2048;
light.shadow.mapSize.height =2048;ABWorld.scene.add( light );// --- Ground ------------------------------------------------------------------var ground_material =Physijs.createMaterial(new THREE.MeshLambertMaterial({ map: ground_texture }),
GROUND_FRICTION,
GROUND_RESTITUTION );
ground_material.map.wrapS = THREE.RepeatWrapping;
ground_material.map.wrapT = THREE.RepeatWrapping;
ground_material.map.repeat.set(3,3);var ground =newPhysijs.BoxMesh(new THREE.BoxGeometry( GROUNDSIZE,1, GROUNDSIZE ),
ground_material,0);// mass
ground.receiveShadow =true;ABWorld.scene.add( ground );// start infinite loop - but maybe neutralised until splashClicked is true ABWorld.render();
console.log ("Resources loaded.");
resourcesLoaded =true;
createBox();}function createBox(){// has to be started by resourcesLoaded code // cannot be started by splashClicked code since that is outside World // needs both to be true if( resourcesLoaded && splashClicked ){// think each box needs its own material var box_material_0 =Physijs.createMaterial(new THREE.MeshLambertMaterial({ map: box_texture_0 }),
BOX_FRICTION,
BOX_RESTITUTION );var box_geometry =new THREE.BoxGeometry( BOXSIZE, BOXSIZE, BOXSIZE );var box =newPhysijs.BoxMesh( box_geometry, box_material_0 );
box.collisions =0;
box.castShadow =true;
box.position.set( AB.randomIntAtoB(-BOXPOS,BOXPOS), BOXHEIGHT, AB.randomIntAtoB(-BOXPOS,BOXPOS));
box.rotation.set(Math.random()*Math.PI,Math.random()*Math.PI,Math.random()*Math.PI );
box.addEventListener('collision',function( other_object, relative_velocity, relative_rotation, contact_normal )// box has collided with other_object with an impact speed of relative_velocity and a rotational force of relative_rotation and at normal contact_normal{// console.log ( relative_velocity );var mainImpact = relative_velocity.y;// impact in direction of gravity // console.log ( Math.abs(mainImpact) );if(Math.abs(mainImpact)> HEAVYIMPACT )// main impact, not lesser ones as it settles {
soundCollision();var box_material_1 =Physijs.createMaterial(new THREE.MeshLambertMaterial({ map: box_texture_1 }),
BOX_FRICTION,
BOX_RESTITUTION );this.material = box_material_1;}});ABWorld.scene.add( box );
currentbox = box;
boxno++;}// --- call createBox again -----------------------------------------------------
setTimeout ( createBox, nextboxin());// Create next box in some random time.// Put this in createBox, not nextStep - runs on independent timer. }
AB.world.newRun =function(){ABWorld.init3d ( startRadius, maxRadius, SKYCOLOR );// sets up renderer, scene, camera// can adjust renderer:ABWorld.renderer.shadowMap.enabled =true;// scene is Physijs.Scene, not THREE.Scene// can adjust scene - change gravity from default:ABWorld.scene.setGravity ( gravity );// multiply mouse scrolls by some factor to speed up/slow down movement:// ABHandler.SCROLLFACTOR = 0.1;
loadResources();// asynchronous file loads // calls initScene() when all done ABWorld.lookat.copy (ABWorld.scene.position );ABWorld.scene.simulate();// Physics simulate - runs on independent timer to AB nextStep};
AB.world.nextStep =function(){// not much to do each step// physics simulate runs on independent timer// create box runs on another independent timer// for camera control, follow current falling box, whose position changes constantly: if( currentbox )ABWorld.follow.copy ( currentbox.position );if( boxno >0){// AB.msg ( "Box " + boxno + " position: <tt> " + AB.vector3toString ( currentbox.position ) + "</tt>" );
AB.msg ("Box "+ boxno +" height: <tt> "+Math.floor(currentbox.position.y)+"</tt>");}};// --- audio --------------------------------------------------------------function soundCollision(){var audio =newAudio( SOUND_COLLISION );
audio.play();}function soundBeep(){var audio =newAudio( SOUND_BEEP );
audio.play();}// --- Splash screen --------------------------------------------------------------// Splash screen is to try to get audio events to autoplay on mobile/Chrome.// This is a simple version. It just tries one audio event (beep) after user interaction, and hopes other audio will now work.// This simple approach works on some mobile browsers - touch splash screen allows all subsequent audios.// But does not work on other mobile browsers - touch splash screen plays first audio, but subsequent audios are still silent. // display splash screen
AB.newSplash ("Demo of Physics API");// when user clicks/touches button on splash screen, audio starts and run starts:
AB.splashClick (function(){
soundBeep();// audio linked to user interaction
AB.removeSplash();// remove splash screen
splashClicked =true;// will cause createBox to work (if resourcesLoaded is true)});