// Physijs based World
// Bouncy balls
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 interval
const BALLHEIGHT = BALLSIZE * 10 ; // y start position of balls
const HEAVYIMPACT = BALLHEIGHT * 1.2 ; // heavy impacts have y velocity greater than this
const GROUNDSIZE = BALLSIZE * 50;
const startRadius = BALLSIZE * 30 ;
const maxRadius = BALLSIZE * 250 ;
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"
];
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.html
const SKYCOLOR = 0xffffcc;
const LOW_FRICTION = 0.1;
const MEDIUM_FRICTION = 0.5;
const HIGH_FRICTION = 0.95;
const LOW_RESTITUTION = 0.1;
const MEDIUM_RESTITUTION = 0.5;
const HIGH_RESTITUTION = 0.95;
function randomfloatAtoB ( A, B )
{
return ( A + ( Math.random() * (B-A) ) );
}
function randomintAtoB ( A, B )
{
return ( Math.round ( randomfloatAtoB ( A, B ) ) );
}
function World() {
var textureArray;
function initScene()
{
// --- 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( threeworld.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 = 4096;
light.shadow.mapSize.height = 4096;
light.shadow.bias = -0.0001;
threeworld.scene.add( light );
// --- Ground ------------------------------------------------------------------
var ground_material, ground;
var loader = new THREE.TextureLoader();
ground_material = Physijs.createMaterial(
// new THREE.MeshBasicMaterial( { color: 0xdddddd } ),
new THREE.MeshLambertMaterial({ map: loader.load( TEXTURE_GROUND ) }),
LOW_FRICTION,
HIGH_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 plane
ground = new Physijs.PlaneMesh (
new THREE.PlaneGeometry ( GROUNDSIZE, GROUNDSIZE ),
ground_material );
ground.rotation.x = (Math.PI / 2) * 3;
/*
// ground as box does not seem to allow bounces
ground = new Physijs.BoxMesh (
new THREE.BoxGeometry ( GROUNDSIZE, 1, GROUNDSIZE ),
ground_material,
0 );
*/
ground.receiveShadow = true;
threeworld.scene.add( ground );
// --- first ball ------------------------------------------------------------------
textureArray = [
( new THREE.ImageUtils.loadTexture( FILE_ARRAY[0] ) ),
( new THREE.ImageUtils.loadTexture( FILE_ARRAY[1] ) ),
( new THREE.ImageUtils.loadTexture( FILE_ARRAY[2] ) ),
( new THREE.ImageUtils.loadTexture( FILE_ARRAY[3] ) ),
( new THREE.ImageUtils.loadTexture( FILE_ARRAY[4] ) )
];
createBall();
}
function randomElementOfArray ( a )
{
var i = randomintAtoB ( 0, a.length - 1 );
return ( a[i] );
}
function createBall()
{
// (subtle bug) apparently each ball needs its own material if it is to bounce separately
var ball_material = Physijs.createMaterial (
new THREE.MeshLambertMaterial({ map: randomElementOfArray(textureArray) }),
LOW_FRICTION,
HIGH_RESTITUTION );
var ball = new Physijs.SphereMesh (
new THREE.SphereGeometry( BALLSIZE, 20, 20 ),
ball_material,
1 ); // mass
ball.collisions = 0;
ball.castShadow = true;
ball.position.set( randomintAtoB(-BALLPOS,BALLPOS), BALLHEIGHT, 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();
}
});
threeworld.scene.add( ball );
setTimeout( createBall, randomintAtoB ( 200, 1000 ) );
}
function soundCollision()
{
var x = "<audio src=" + SOUND_COLLISION + " autoplay > </audio>";
$("#user_span2").html( x );
}
// --- public interface ----------------------------------------------------------------------
this.endCondition;
this.newRun = function()
{
this.endCondition = false;
threeworld.init3d ( startRadius, maxRadius, SKYCOLOR );
// sets up renderer, scene, camera
// can adjust renderer:
threeworld.renderer.shadowMap.enabled = true;
// scene is Physijs.Scene, not THREE.Scene
// can adjust scene - change gravity from default:
threeworld.scene.setGravity ( new THREE.Vector3( 0, -50, 0 ));
initScene();
threeworld.lookat.copy ( threeworld.scene.position );
threeworld.scene.simulate(); // Physics simulate - runs on independent timer to AB nextStep
};
this.nextStep = function()
{
};
this.endRun = function()
{
};
}