// Cloned by test on 21 Feb 2019 from World "Bouncy Balls" by Starter user // Please leave this clone trail here.// ==== Starter World ===============================================================================================// (c) Ancient Brain Ltd. All rights reserved.// This code is only for use on the Ancient Brain site.// This code may be freely copied and edited by anyone on the Ancient Brain site.// This code may not be copied, re-published or used on any other website.// To include a run of this code on another website, see the "Embed code" links provided on the Ancient Brain site.// ==================================================================================================================// Physijs based World// Bouncy balls // ===================================================================================================================// === 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.screenshotStep =200;// Take screenshot on this step. (All resources should have finished loading.) Default 50.const BALLSIZE =5;const BALLPOS = BALLSIZE *2;// x,z start position of balls is random in this intervalconst BALLHEIGHT = BALLSIZE *10;// y start position of balls const HEAVYIMPACT =60;// heavy impacts have y velocity greater than this const GROUNDSIZE = BALLSIZE *50;const startRadius = BALLSIZE *30;const maxRadius = BALLSIZE *250;const TEXTURE_GROUND ='/uploads/starter/rocks.jpg';// const TEXTURE_GROUND = '/uploads/starter/latin.jpg' ;const SOUND_COLLISION ='/uploads/starter/bounce.mp3';// credit:// http://soundbible.com/1343-Jump.htmlconst SKYCOLOR =0xffffcc;// friction and restitution between 0 and 1: const GROUND_FRICTION =1;const GROUND_RESTITUTION =0;const BALL_FRICTION =1;const BALL_RESTITUTION =0;// define gravity along x,y,z dimensions:var gravity =new THREE.Vector3(0,-100,0);const BALL_MASS =1;function nextballin()// Speed of ball creation // Create next ball in some random (m to n) milliseconds time.{// return ( AB.randomIntAtoB ( 2000, 4000 ) ); return( AB.randomIntAtoB (200,1000));}const FILE_ARRAY =["/uploads/starter/earth.1.jpg","/uploads/starter/earth.2.jpg","/uploads/starter/earth.3.jpg","/uploads/starter/earth.4.jpg","/uploads/starter/earth.5.jpg"];ABWorld.drawCameraControls =false;// ===================================================================================================================// === 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;functionWorld(){var textureArray =newArray( FILE_ARRAY.length );var ground_texture ;var self =this;function loadResources()// asynchronous file loads - call initScene() when all finished {var loader =new THREE.TextureLoader();
loader.load ( TEXTURE_GROUND,function( thetexture )// asynchronous file load{
thetexture.minFilter = THREE.LinearFilter;
ground_texture = thetexture;if( asynchFinished()) initScene();});for(var i =0; i < FILE_ARRAY.length; i++)
startFileLoad ( i );// start n more asynchronous file loads }function startFileLoad ( n )// asynchronous file load of texture n {var loader =new THREE.TextureLoader();
loader.load ( FILE_ARRAY[n],function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
textureArray[n]= thetexture;if( asynchFinished()) initScene();});}function asynchFinished()// all file loads returned {if(! ground_texture )returnfalse;for(var i =0; i < FILE_ARRAY.length; i++)if(! textureArray[i])returnfalse;returntrue;}function initScene()// all file loads have returned {// --- Light ------------------------------------------------------------------var light =new THREE.DirectionalLight(0xFFFFFF,1.3);// close to origin, high up, works best for shadows
light.position.set( BALLHEIGHT,(BALLHEIGHT *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;// higher quality shadows at expense of computation time:
light.shadow.mapSize.width =2048;
light.shadow.mapSize.height =2048;
light.shadow.bias =-0.0001;ABWorld.scene.add( light );// --- Ground ------------------------------------------------------------------var ground_material =Physijs.createMaterial(// new THREE.MeshBasicMaterial( { color: 0xdddddd } ),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);// ground as plane allows bounces but seems to be infinite planevar ground =newPhysijs.PlaneMesh(new THREE.PlaneGeometry( GROUNDSIZE, GROUNDSIZE ),
ground_material );
ground.rotation.x =(Math.PI /2)*3;/*
// ground as box is finite (beyond it, things fall into the void)
// but it does not seem to allow bounces
ground = new Physijs.BoxMesh (
new THREE.BoxGeometry ( GROUNDSIZE, 1, GROUNDSIZE ),
ground_material,
0 );
*/
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;
createBall();}function createBall(){if( resourcesLoaded && splashClicked ){// (subtle bug) apparently each ball needs its own material if it is to bounce separatelyvar ball_material =Physijs.createMaterial (new THREE.MeshLambertMaterial({ map: AB.randomElementOfArray(textureArray)}),
BALL_FRICTION,
BALL_RESTITUTION );var ball_geometry =new THREE.SphereGeometry( BALLSIZE,20,20);var ball =newPhysijs.SphereMesh( ball_geometry, ball_material, BALL_MASS );
ball.collisions =0;
ball.castShadow =true;
ball.position.set( AB.randomIntAtoB(-BALLPOS,BALLPOS), BALLHEIGHT, AB.randomIntAtoB(-BALLPOS,BALLPOS));
ball.addEventListener('collision',function( other_object, relative_velocity, relative_rotation, contact_normal ){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();}});ABWorld.scene.add( ball );}// --- call createBall again -----------------------------------------------------
setTimeout ( createBall, nextballin());// set to create next ball in some random time }// --- public interface ----------------------------------------------------------------------this.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 );
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};this.nextStep =function()// not used {};}// --- audio --------------------------------------------------------------// This is a more sophisticated solution to get audio autoplay on mobile/Chrome.// Splash screen forces user interaction, which marks *multiple* audio global variables as "approved" for later play.// Then when we need to play audio, find one of these global variables that is not already playing, and play it.// global variable audio objects:var theaudio1 =newAudio( SOUND_COLLISION );var theaudio2 =newAudio( SOUND_COLLISION );var theaudio3 =newAudio( SOUND_COLLISION );var theaudio4 =newAudio( SOUND_COLLISION );var theaudio5 =newAudio( SOUND_COLLISION );function soundCollision()// triggered by JS, not by user interaction {if(! AB.audioIsPlaying ( theaudio1 )){ theaudio1.play();return;}if(! AB.audioIsPlaying ( theaudio2 )){ theaudio2.play();return;}if(! AB.audioIsPlaying ( theaudio3 )){ theaudio3.play();return;}if(! AB.audioIsPlaying ( theaudio4 )){ theaudio4.play();return;}if(! AB.audioIsPlaying ( theaudio5 )){ theaudio5.play();return;}// else try to make a new one, local variable, without user interaction// but this will not play on some browsers:var a =newAudio( SOUND_COLLISION );
a.play();}// --- Splash screen --------------------------------------------------------------
AB.newSplash ("Demo of Physics API");// when user clicks/touches button on splash screen, audio starts and run starts:
$("#splashbutton").click (function(){// mark multiple audio objects as good now for JS to call play() without further user interaction:
theaudio1.play(); theaudio1.pause();
theaudio2.play(); theaudio2.pause();
theaudio3.play(); theaudio3.pause();
theaudio4.play(); theaudio4.pause();
theaudio5.play(); theaudio5.pause();
AB.removeSplash();// remove splash screen
splashClicked =true;});