// Cloned by Ian Gilligan on 16 Feb 2019 from World "v0.5 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 14 Feb 2019 from World "v0.44 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 12 Feb 2019 from World "v0.43 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 5 Feb 2019 from World "v0.3 Pool Predictor Prototype" by lillisl2
// Please leave this clone trail here.
// Cloned by lillisl2 on 4 Feb 2019 from World "v0.2 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 1 Feb 2019 from World "lillisl2 0.2 Pool Predictor Prototype" by lillisl2
// Please leave this clone trail here.
// Cloned by lillisl2 on 1 Feb 2019 from World "0.1 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 30 Jan 2019 from World "Pool Predictor Prototype" by lillisl2
// Please leave this clone trail here.
// Cloned by lillisl2 on 28 Jan 2019 from World "Cloned Bouncy Balls" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 28 Jan 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 = 50;
// Take screenshot on this step. (All resources should have finished loading.) Default 50.
// ===================================================================================================================
// === Variables & Constants =========================================================================================
// ===================================================================================================================
const OBJPATH = "/uploads/gilligi2/"; // path of OBJ and MTL
const OBJNAME = "PoolTable.obj";
const MTLNAME = "pooltable.mtl";
const MODELLENGTH = 11054;
const MODELWIDTH = 6279;
const SCALE = 0.009;
const BALLSIZE = 2; // size of each ball
const BALLPOS = BALLSIZE * 100; // x,z start position of balls is random in this interval
const BALLHEIGHT = BALLSIZE * 2; // y start position of balls
const HEAVYIMPACT = 10; // heavy impacts have y velocity greater than this
const GROUNDSIZE = 150; // size of table
const startRadius = MODELWIDTH * 0.02; // camera start distance
const maxRadius = MODELLENGTH * 0.03; // camera max distance
const TEXTURE_GROUND = "/uploads/gilligi2/8451323128.png"; //colour of ground (green)
const TEXTURE_WALL = "/uploads/lillisl2/8451232143.png"; //colour of walls (brown)
const SKYCOLOR = 0xffffff; //colour of sky / background (white)
// friction and restitution between 0 and 1:
var GROUND_FRICTION = 1; // friction of ground
const GROUND_RESTITUTION = 0.5; // restitution of ground
const WALL_FRICTION = 1; // friction of wall
const WALL_RESTITUTION = 0.5; // restitution of wall
const BALL_FRICTION = 0.9; // friction of ball
const BALL_RESTITUTION = 0.8; // restitution of ball
var LIMIT = [7,7,1,1]; // limit values of each type of balls [yellow, red, black, white]
var BALL_CHOICE = 0; // the ball that the user has currently selected
const BALL_TYPE = [ // what each value of ball choice (0-3) represent
"Yellow",
"Red",
"Black",
"White"];
// define gravity along x,y,z dimensions:
var gravity = new THREE.Vector3 (0, -100, 0);
const BALL_MASS = 10; // mass of ball
const FILE_ARRAY = [ // colours of each ball [yellow, red, black, white]
"/uploads/gilligi2/8451323595.png",
"/uploads/gilligi2/8451323612.png",
"/uploads/gilligi2/8451147306.png",
"/uploads/gilligi2/8451147292.png"];
const BASE_POWER = 10000;
var MIN_POWER = 1;
var MAX_POWER = 5;
var difficulty = "Easy";
var YOURCOLOR = "None";
var CALCULATED = false;
var BALL_COUNT = 0;
var BALLS = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var WHITE = -1;
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;
function World()
{
var textureArray = new Array ( FILE_ARRAY.length );
var ground_texture;
var self = this;
var GROUND;
var table;
var p_height = 25;
function loadResources() // asynchronous file loads - call initScene() when all finished
{
var m = new THREE.MTLLoader();
m.setTexturePath (OBJPATH);
m.setPath (OBJPATH);
m.load ( MTLNAME, function ( materials )
{
materials.preload();
var o = new THREE.OBJLoader();
o.setMaterials ( materials );
o.setPath ( OBJPATH );
o.load ( OBJNAME, function ( object )
{
table = object;
if ( asynchFinished() ) initScene();
});
});
for (var j = 0; j < FILE_ARRAY.length; j++){
startFileLoad (j);}}
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 (! table){
return false;}
return true;}
function initScene() // all file loads have returned
{
// --- Light ------------------------------------------------------------------
var light = new THREE.DirectionalLight(0xFFFFFF, 0.7);
// close to origin, high up, works best for shadows
light.position.set(0, 40, 0);
light.target.position.copy(ABWorld.scene.position);
light.castShadow = true;
// how far away to draw shadows:
light.shadow.camera.left = -20;
light.shadow.camera.right = 20;
light.shadow.camera.bottom = -20;
light.shadow.camera.top = 20;
// higher quality shadows at expense of computation time:
light.shadow.mapSize.width = 2048;
light.shadow.mapSize.height = 2048;
light.shadow.bias = -0.1;
ABWorld.scene.add(light);
// --- Table -------------------------------------------------------------------
table.position.y = 0;
table.position.x = -15;
table.position.z = 0;
ABWorld.scene.add(table);
// --- Ground ------------------------------------------------------------------
var ground_material = Physijs.createMaterial(new THREE.MeshStandardMaterial(), GROUND_FRICTION, GROUND_RESTITUTION);
// ground as plane allows bounces but seems to be infinite plane
var ground = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE, 1, MODELWIDTH * SCALE), ground_material, 0);
ground.position.y = p_height;
ground.collisions = 0;
ground.receiveShadow = true;
//ABWorld.scene.add(ground);
GROUND = ground;
// --- Wall --------------------------------------------------------------------
var wall_material = Physijs.createMaterial(new THREE.MeshStandardMaterial(), WALL_FRICTION, WALL_RESTITUTION);
var wall1 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE, 6, MODELWIDTH * SCALE * 0.075), wall_material, 0);
wall1.position.z = 28;
wall1.collisions = 0;
wall1.receiveShadow = true;
var wall2 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE, 6, MODELWIDTH * SCALE * 0.075), wall_material, 0);
wall2.position.z = -28;
wall2.collisions = 0;
wall2.receiveShadow = true;
var wall3 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.05, 6, MODELWIDTH * SCALE), wall_material, 0);
wall3.position.x = 52;
wall3.collisions = 0;
wall3.receiveShadow = true;
var wall4 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.05, 6, MODELWIDTH * SCALE), wall_material, 0);
wall4.position.x = -52;
wall4.collisions = 0;
wall4.receiveShadow = true;
// --- Bumper --------------------------------------------------------------------
var bumper1 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.35, 6, MODELWIDTH * SCALE * 0.075 * 1.5), wall_material, 0);
bumper1.position.z = 23.5;
bumper1.position.x = 23.5;
bumper1.position.y = -0.1;
bumper1.collisions = 0;
bumper1.receiveShadow = true;
var bumper2 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.35, 6, MODELWIDTH * SCALE * 0.075 * 1.5), wall_material, 0);
bumper2.position.z = 23.5;
bumper2.position.x = -23.5;
bumper2.collisions = 0;
bumper2.receiveShadow = true;
var bumper3 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.35, 6, MODELWIDTH * SCALE * 0.075 * 1.5), wall_material, 0);
bumper3.position.z = -23.5;
bumper3.position.x = 23.5;
bumper3.position.y = -0.1;
bumper3.collisions = 0;
bumper3.receiveShadow = true;
var bumper4 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.35, 6, MODELWIDTH * SCALE * 0.075 * 1.5), wall_material, 0);
bumper4.position.z = -23.5;
bumper4.position.x = -23.5;
bumper4.collisions = 0;
bumper4.receiveShadow = true;
var bumper5 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.03, 6, MODELWIDTH * SCALE * 0.55), wall_material, 0);
bumper5.position.z = 0;
bumper5.position.x = 48;
bumper5.receiveShadow = true;
var bumper6 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.03, 6, MODELWIDTH * SCALE * 0.55), wall_material, 0);
bumper6.position.z = 0;
bumper6.position.x = -48;
bumper6.receiveShadow = true;
ground.add(wall1);
ground.add(wall2);
ground.add(wall3);
ground.add(wall4);
ground.add(bumper1);
ground.add(bumper2);
ground.add(bumper3);
ground.add(bumper4);
ground.add(bumper5);
ground.add(bumper6);
ABWorld.scene.add(ground);
var pocket_material = Physijs.createMaterial(new THREE.MeshStandardMaterial());
var pocket1 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
pocket1.position.y = p_height;
pocket1.position.z = 21.5;
pocket1.position.x = 47;
pocket1.addEventListener('collision', function(other_object, relative_velocity, relative_rotation, contact_normal)
{
ABWorld.scene.remove(other_object);
})
var pocket2 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
pocket2.position.y = p_height;
pocket2.position.z = -21.5;
pocket2.position.x = 47;
pocket2.addEventListener('collision', function(other_object, relative_velocity, relative_rotation, contact_normal)
{
ABWorld.scene.remove(other_object);
})
var pocket3 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
pocket3.position.y = p_height;
pocket3.position.z = 24;
pocket3.addEventListener('collision', function(other_object, relative_velocity, relative_rotation, contact_normal)
{
ABWorld.scene.remove(other_object);
})
var pocket4 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
pocket4.position.y = p_height;
pocket4.position.z = 21.5;
pocket4.position.x = -47;
pocket4.addEventListener('collision', function(other_object, relative_velocity, relative_rotation, contact_normal)
{
ABWorld.scene.remove(other_object);
})
var pocket5 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
pocket5.position.y = p_height;
pocket5.position.z = -21.5;
pocket5.position.x = -47;
pocket5.addEventListener('collision', function(other_object, relative_velocity, relative_rotation, contact_normal)
{
ABWorld.scene.remove(other_object);
})
var pocket6 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
pocket6.position.y = p_height;
pocket6.position.z = -24;
pocket6.addEventListener('collision', function(other_object, relative_velocity, relative_rotation, contact_normal)
{
ABWorld.scene.remove(other_object);
})
ABWorld.scene.add(pocket1);
ABWorld.scene.add(pocket2);
ABWorld.scene.add(pocket3);
ABWorld.scene.add(pocket4);
ABWorld.scene.add(pocket5);
ABWorld.scene.add(pocket6);
ABWorld.render();
console.log("Resources loaded.");
resourcesLoaded = true;}
function increaseFriction(){
if (GROUND_FRICTION + 0.05 < 1.0){
GROUND_FRICTION += 0.05;}
else {GROUND_FRICTION = 1.0;}
}
function decreaseFriction(){
if (GROUND_FRICTION - 0.05 > 0.0){
GROUND_FRICTION -= 0.05;}
else {GROUND_FRICTION = 0.0;}
}
function decreasePowerMin(){
if (MIN_POWER > 1) {MIN_POWER -= 1;}}
function increasePowerMin(){
if (MIN_POWER < MAX_POWER) {MIN_POWER += 1;}}
function decreasePowerMax(){
if (MIN_POWER < MAX_POWER) {MAX_POWER -= 1;}}
function increasePowerMax(){
if (MAX_POWER < 5) {MAX_POWER += 1;}}
function selectBall(x)
{
BALL_CHOICE = x;}
function setDifficulty(x){
difficulty = x;
}
function setColor(x){
YOURCOLOR = x;
}
function hitBall()
{
if (WHITE != -1){
var white_b = (BALLS[WHITE][0]);
white_b.applyCentralForce(new THREE.Vector3 (BASE_POWER * (MIN_POWER * 2), 0, 0));
}
//console.log(Math.abs(mainImpact));
}
function basicSetUp()
{
if (BALL_COUNT === 0){
var tmp_choice = BALL_CHOICE;
BALL_CHOICE = 3;
createBall(-30, p_height + 0.5, 0);
BALL_CHOICE = 2;
createBall(30, p_height + 0.5, 0);
BALL_CHOICE = 1;
createBall(23, p_height + 0.5, 0); //red
createBall(26.5, p_height + 0.5, -2); //red
createBall(30, p_height + 0.5, 4); //red
createBall(33.5, p_height + 0.5, 2); //red
createBall(33.5, p_height + 0.5, -6); // red
createBall(37, p_height + 0.5, -4); //red
createBall(37, p_height + 0.5, 8); //red
BALL_CHOICE = 0;
createBall(26.5, p_height + 0.5, 2); //yellow
createBall(30, p_height + 0.5, -4); //yellow
createBall(33.5, p_height + 0.5, -2); //yellow
createBall(33.5, p_height + 0.5, 6); //yellow
createBall(37, p_height + 0.5, 0); //yellow
createBall(37, p_height + 0.5, 4); //yellow
createBall(37, p_height + 0.5, -8); //yellow
BALL_CHOICE = tmp_choice;
}
}
function createBall(x, y, z)
{
if ( resourcesLoaded && splashClicked && LIMIT[BALL_CHOICE] !== 0)
{
var ball_material = Physijs.createMaterial(new THREE.MeshLambertMaterial({map: textureArray[BALL_CHOICE]}), BALL_FRICTION, BALL_RESTITUTION);
var ball_geometry = new THREE.SphereGeometry(BALLSIZE, 100, 100);
var ball = new Physijs.SphereMesh(ball_geometry, ball_material, BALL_MASS);
ball.collisions = 0;
ball.castShadow = true;
//ball.position.set(1, 40, 1);
ball.position.set(x, y + 2, z);
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();
}
});
BALLS[BALL_COUNT] = [ball, BALL_CHOICE];
if (BALL_CHOICE == 3){
WHITE = BALL_COUNT;
}
BALL_COUNT += 1;
ABWorld.scene.add(ball);
LIMIT[BALL_CHOICE] -= 1;
}
}
var OURKEYS = [49, 50, 51, 52];
function ourKeys(event) {return(OURKEYS.includes(event.keyCode));}
function keyHandler(event)
{
if (! ABRun.runReady) {return true;} // not ready yet
// if not handling this key, send it to default:
if (! ourKeys(event)) {return true;}
// else handle it and prevent default:
if ( event.keyCode == 49 ) {selectBall(0);}
else if ( event.keyCode == 50 ) {selectBall(1);}
else if ( event.keyCode == 51 ) {selectBall(2);}
else if ( event.keyCode == 52 ) {selectBall(3);}
event.stopPropagation(); event.preventDefault(); return false;
}
var startX, startY;
var dragevents; // number of events in the current drag
function click(event)
{
var object = (ABWorld.hitsObjectPoint(event.x, event.y, GROUND)); // returns null if no hit
if (object !== null){
createBall(object.x, object.y, object.z);}}
//for future drag functionality
//function initDrag (x, y)
//{}
//function drag (x, y)
//{}
function initPreOptions()
{
var s = "<p align=\"center\"><button id='yellowButton'>Yellow</button> <button id='redButton'>Red</button> <button id='blackButton'>Black</button> <button id='whiteButton'>White</button></p>";
$("#user_span2").html(s);
s ="<p align=\"center\"><button id='decreaseFrictionButton'>-</button> <button id='increaseFrictionButton'>+</button></p> ";
$("#user_span4").html(s);
s ="<p align=\"center\"><button id='decreasePowerMinButton'>- Min</button> <button id='increasePowerMinButton'>+ Min</button> <button id='decreasePowerMaxButton'>- Max</button> <button id='increasePowerMaxButton'>+ Max</button></p> ";
$("#user_span6").html(s);
//s = "<p align=\"center\"><button id='easyButton'>Easy</button> <button id='mediumButton'>Medium</button> <button id='hardButton'>Hard</button></p>";
s = "<p align=\"center\"><button id='basicSetUp'>Basic Set Up</button></p>";
$("#user_span8").html(s);
//s ="<p align=\"center\"><button id='yourNButton'>None</button> <button id='yourYButton'>Yellow</button> <button id='yourRButton'>Red</button></p>";
s = "<p align=\"center\"><button id='hitBall'>GO!</button></p>";
$("#user_span10").html(s);
//colour pick events
document.getElementById("yellowButton").addEventListener("click", function() { selectBall(0); }, false);
document.getElementById("redButton").addEventListener("click", function() { selectBall(1); }, false);
document.getElementById("blackButton").addEventListener("click", function() { selectBall(2); }, false);
document.getElementById("whiteButton").addEventListener("click", function() { selectBall(3); }, false);
//friction choice events
document.getElementById("decreaseFrictionButton").addEventListener("click", function() { decreaseFriction(); }, false);
document.getElementById("increaseFrictionButton").addEventListener("click", function() { increaseFriction(); }, false);
//power choice events
document.getElementById("decreasePowerMinButton").addEventListener("click", function() { decreasePowerMin(); }, false);
document.getElementById("increasePowerMinButton").addEventListener("click", function() { increasePowerMin(); }, false);
document.getElementById("decreasePowerMaxButton").addEventListener("click", function() { decreasePowerMax(); }, false);
document.getElementById("increasePowerMaxButton").addEventListener("click", function() { increasePowerMax(); }, false);
//set difficulty
//document.getElementById("easyButton").addEventListener("click", function() { setDifficulty("Easy"); }, false);
//document.getElementById("mediumButton").addEventListener("click", function() { setDifficulty("Medium"); }, false);
//document.getElementById("hardButton").addEventListener("click", function() { setDifficulty("Hard"); }, false);
// set the colour of balls your playing as
//document.getElementById("yourNButton").addEventListener("click", function() { setColor("None"); }, false);
//document.getElementById("yourYButton").addEventListener("click", function() { setColor("Yellow"); }, false);
//document.getElementById("yourRButton").addEventListener("click", function() { setColor("Red"); }, false);
//document.getElementById("idButton").addEventListener("click", function() { func(var); }, false);
document.getElementById("basicSetUp").addEventListener("click", function() { basicSetUp();}, false);
document.getElementById("hitBall").addEventListener("click", function() { hitBall();}, false);
}
function initPostOptions()
{
}
function updatePreHUD()
{
$("#user_span1").html("<p align=\"center\">Ball Selected: <b>"+ BALL_TYPE[BALL_CHOICE] + "</b></p>");
$("#user_span3").html("<p align=\"center\">Ground Friction: <b>" + Number.parseFloat(GROUND_FRICTION).toFixed(2) + "</b></p>");
$("#user_span5").html("<p align=\"center\">Power: <b>" + MIN_POWER + " to " + MAX_POWER + "</b></p>");
$("#user_span7").html("<p align=\"center\">The Difficultly is set to: <b>" + difficulty + "</b></p>");
$("#user_span9").html("<p align=\"center\">Your Color: <b>" + YOURCOLOR + "</b></p>");
}
// --- public interface ----------------------------------------------------------------------
this.newRun = function()
{
ABWorld.init3d(startRadius, maxRadius, SKYCOLOR); // sets up renderer, scene, camera
initPreOptions();
// 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
// user actions
document.onkeydown = keyHandler;
document.ondblclick = click;
//ABHandler.initTouchDrag = initDrag;
//ABHandler.touchDrag = drag
//ABHandler.initMouseDrag = initDrag;
//ABHandler.mouseDrag = drag
};
this.nextStep = function() // not used
{
if (CALCULATED === false){
updatePreHUD();}
else {
initPostOptions();
updatePostHUD();}
};
}
// --- Splash screen --------------------------------------------------------------
AB.newSplash ("Demo of Physics API");
// when user clicks/touches button on splash screen, audio starts and run starts:
$("#splashbutton").click (function()
{
AB.removeSplash(); // remove splash screen
splashClicked = true;
});