// Cloned by lillisl2 on 28 Feb 2019 from World "v0.98 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 28 Feb 2019 from World "v0.97 Pool Predictor Prototype" by lillisl2
// Please leave this clone trail here.
// Cloned by lillisl2 on 27 Feb 2019 from World "v0.95 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 25 Feb 2019 from World "v0.94 Pool Predictor Prototype" by lillisl2
// Please leave this clone trail here.
// Cloned by lillisl2 on 25 Feb 2019 from World "v0.94 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 25 Feb 2019 from World "v0.92 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 20 Feb 2019 from World "v0.91 Pool Predictor Prototype" by lillisl2
// Please leave this clone trail here.
// Cloned by lillisl2 on 20 Feb 2019 from World "v0.9 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 20 Feb 2019 from World "v0.8 Pool Predictor Prototype" by lillisl2
// Please leave this clone trail here.
// Cloned by lillisl2 on 19 Feb 2019 from World "v0.7 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// Cloned by Ian Gilligan on 18 Feb 2019 from World "v0.6 Pool Predictor Prototype" by Ian Gilligan
// Please leave this clone trail here.
// 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 = 0.99; // friction of ground
const GROUND_RESTITUTION = 0.5; // restitution of ground
const WALL_FRICTION = 0.99; // friction of wall
const WALL_RESTITUTION = 0.9; // restitution of wall
const BALL_FRICTION = 0.99; // 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, -150, 0);
const BALL_MASS = 10; // mass of ball
const BASE_POWER = 30000;
var MIN_POWER = 1;
var MAX_POWER = 5;
var difficulty = "Easy";
var YOURCOLOR = "None";
var CALCULATED = false;
var CALCULATING = false;
// == Balls Placed ==
var BALL_COUNT = 0;
var BALLS = [];
var WHITE = -1;
// == Ball Colors ==
const BALL_COLORS = {
0 : "Yellow",
1 : "Red",
2 : "Black",
3 : "White"};
const BALL_COLORS_R = {
"Yellow" : 0,
"Red" : 1,
"Black" : 2,
"White" : 3};
// == Ball Movement ==
var movFin = false;
var last_velocity = 0;
const SLOWFACTOR = 0.1;
// == Score Calculation ==
var WHITE_POT = false;
var BLACK_POT = false;
var firstHit = true;
var YOURSCORE = 0;
var OTHERSCORE = 0;
var FOUL = false;
var setUpScene;
var SCORE = 50;
var ANGLE;
// == Shot Choice ==
var BALLS_TO_POT = 0;
var BALLS_ATTEMPTED = 0;
var BALLS_CHOSEN = 0;
// == Camera ==
ABWorld.drawCameraControls = false;
var cameraPocketCounter = 0;
// == UI ==
var PAGE_SELECT = 1;
var CURRENT_PAGE = 0;
const line4_1 = ("<p align=\"center\"><button id='yellowButton'>Yellow</button> <button id='redButton'>Red</button> <button id='blackButton'>Black</button> <button id='whiteButton'>White</button></p>");
const line4_2 = ("<p align=\"center\"><button id='decreaseFrictionButton'>-</button> <button id='increaseFrictionButton'>+</button></p> ");
const line4_3 = ("<p align=\"center\"><button id='easyButton'>Easy</button> <button id='mediumButton'>Medium</button> <button id='hardButton'>Hard</button></p>");
const line6_1 = ("<p align=\"center\"><button id='yourNButton'>None</button> <button id='yourYButton'>Yellow</button> <button id='yourRButton'>Red</button></p>");
const line6_2 = ("<p align=\"center\"><button id='decreasePowerMinButton'>- Min</button> <button id='increasePowerMinButton'>+ Min</button> <button id='decreasePowerMaxButton'>- Max</button> <button id='increasePowerMaxButton'>+ Max</button></p> ");
const line6_3 = ("<p align=\"center\"><button id='cameraFlatButton'>Flat Down View</button> <button id='cameraCornerButton'>Pocket View</button></p> ");
// == Save ==
BALL_LAYOUT = [];
BEST_SCORES = [];
var toggleBasic = false;
var toggledBasic = false;
// == Post HUD Variables ==
var counter = 0;
// ===================================================================================================================
// === End of tweaker's box ==========================================================================================
// ===================================================================================================================
// You will need to be some sort of JavaScript programmer to change things below the tweaker's box.
// ===================================================================================================================
// === Inits & Loads =================================================================================================
// ===================================================================================================================
var resourcesLoaded = false;
var splashClicked = false;
function World()
{
var ground_texture;
var self = this;
var GROUND;
var table;
var p_height = 25;
// --- Ball ----------------------------------------------------------------------
var ball_material_0 = Physijs.createMaterial(new THREE.MeshLambertMaterial({color : "yellow"}), BALL_FRICTION, BALL_RESTITUTION);
var ball_material_1 = Physijs.createMaterial(new THREE.MeshLambertMaterial({color : "red"}), BALL_FRICTION, BALL_RESTITUTION);
var ball_material_2 = Physijs.createMaterial(new THREE.MeshLambertMaterial({color : "black"}), BALL_FRICTION, BALL_RESTITUTION);
var ball_material_3 = Physijs.createMaterial(new THREE.MeshLambertMaterial({color : "white"}), BALL_FRICTION, BALL_RESTITUTION);
var ball_geometry = new THREE.SphereGeometry(BALLSIZE, 100, 100);
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();
});
});}
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.4);
// 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);
var light1 = new THREE.DirectionalLight(0xFFFFFF, 0.4);
var light2 = new THREE.DirectionalLight(0xFFFFFF, 0.4);
var light3 = new THREE.DirectionalLight(0xFFFFFF, 0.4);
var light4 = new THREE.DirectionalLight(0xFFFFFF, 0.4);
light1.position.set(100, 30, 0);
light2.position.set(-100, 30, 0);
light3.position.set(0, 30, 100);
light4.position.set(0, 30, -100);
ABWorld.scene.add(light1);
ABWorld.scene.add(light2);
ABWorld.scene.add(light3);
ABWorld.scene.add(light4);
// --- 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({wireframe : true}), 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;
// --- Floor -------------------------------------------------------------------
var floor_material = Physijs.createMaterial(new THREE.MeshLambertMaterial({color: "grey"}), 0.1, 0.1);
//floor_material.map.wrapS = THREE.RepeatWrapping;
//floor_material.map.wrapT = THREE.RepeatWrapping;
//floor_material.map.repeat.set(3, 3);
var floor = new Physijs.PlaneMesh(new THREE.PlaneGeometry(1000, 1000), floor_material);
floor.rotation.x = (Math.PI / 2) * 3;
floor.receiveShadow = true;
ABWorld.scene.add(floor);
// --- Wall --------------------------------------------------------------------
var wall_material = Physijs.createMaterial(new THREE.MeshStandardMaterial({wireframe : true}), WALL_FRICTION, WALL_RESTITUTION);
var wall1 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 1.03, 5.9, MODELWIDTH * SCALE * 0.055), wall_material, 0);
wall1.position.z = 27.5;
wall1.collisions = 0;
wall1.receiveShadow = true;
var wall2 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 1.03, 5.9, MODELWIDTH * SCALE * 0.055), wall_material, 0);
wall2.position.z = -27.7;
wall2.collisions = 0;
wall2.receiveShadow = true;
var wall3 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.02, 5.9, MODELWIDTH * SCALE * 0.92), wall_material, 0);
wall3.position.x = 52.2;
wall3.collisions = 0;
wall3.receiveShadow = true;
var wall4 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.02, 5.9, MODELWIDTH * SCALE * 0.92), wall_material, 0);
wall4.position.x = -52.2;
wall4.collisions = 0;
wall4.receiveShadow = true;
// --- Bumper --------------------------------------------------------------------
var bumper1 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.33, 5.9, MODELWIDTH * SCALE * 0.075 * 1.65), 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.33, 5.9, MODELWIDTH * SCALE * 0.075 * 1.65), wall_material, 0);
bumper2.position.z = 23.5;
bumper2.position.x = -23;
bumper2.collisions = 0;
bumper2.receiveShadow = true;
var bumper3 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.33, 5.9, MODELWIDTH * SCALE * 0.075 * 1.58), 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.33, 5.9, MODELWIDTH * SCALE * 0.075 * 1.58), wall_material, 0);
bumper4.position.z = -23.5;
bumper4.position.x = -23;
bumper4.collisions = 0;
bumper4.receiveShadow = true;
var bumper5 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.047, 5.9, MODELWIDTH * SCALE * 0.56), wall_material, 0);
bumper5.position.z = 0;
bumper5.position.x = 49;
bumper5.receiveShadow = true;
var bumper6 = new Physijs.BoxMesh(new THREE.BoxGeometry(MODELLENGTH * SCALE * 0.047, 5.9, MODELWIDTH * SCALE * 0.56), wall_material, 0);
bumper6.position.z = 0;
bumper6.position.x = -49;
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);
//ground.visible = false;
ABWorld.scene.add(ground);
// --- Pocket --------------------------------------------------------------------
var pocket_material = Physijs.createMaterial(new THREE.MeshStandardMaterial());
var pocket = new Physijs.SphereMesh(new THREE.SphereGeometry(1), pocket_material, 0);
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;
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;
var pocket3 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
pocket3.position.y = p_height;
pocket3.position.z = 24;
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;
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;
var pocket6 = new Physijs.SphereMesh(new THREE.SphereGeometry(3, 15, 15), pocket_material, 0);
pocket6.position.y = p_height;
pocket6.position.z = -24;
pocket.add(pocket1);
pocket.add(pocket2);
pocket.add(pocket3);
pocket.add(pocket4);
pocket.add(pocket5);
pocket.add(pocket6);
pocket.addEventListener('collision', function(other_object, relative_velocity, relative_rotation, contact_normal)
{
removeBall(other_object);
});
pocket.visible = false;
ABWorld.scene.add(pocket);
ABWorld.render();
console.log("Resources loaded.");
resourcesLoaded = true;}
// ===================================================================================================================
// === Button Functions ==============================================================================================
// ===================================================================================================================
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 pageChange(x){
PAGE_SELECT = x;
}
function cameraFlatDown(){
ABWorld.camera.position.set(0,100,0);
}
function cameraSomeCornerPocket(){
if (cameraPocketCounter % 4 === 0){
ABWorld.camera.position.set(50,50,30);
}
else if (cameraPocketCounter % 4 == 1){
ABWorld.camera.position.set(50,50,-30);
}
else if(cameraPocketCounter % 4 == 2){
ABWorld.camera.position.set(-50,50,-30);
}
else if(cameraPocketCounter % 4 == 3){
ABWorld.camera.position.set(-50,50, 30);
}
cameraPocketCounter = cameraPocketCounter + 1;
}
// ===================================================================================================================
// === Shot Calculations =============================================================================================
// ===================================================================================================================
function calculateShot()
{
prepareHit();
CALCULATING = true;
}
function prepareHit()
{
if (YOURCOLOR == "None"){
BALLS_TO_POT = 14;
}
else if (YOURCOLOR != "None"){
BALLS_TO_POT = colorCount(YOURCOLOR);
if (BALLS_TO_POT === 0){
BALLS_TO_POT = 1;
}
}
BALLS_ATTEMPTED = 0;
if (toggledBasic === false){
for (var i in BALLS){
var x = BALLS[i].position.x;
var z = BALLS[i].position.z;
var name = BALLS[i].name;
BALL_LAYOUT.push([x, p_height + 0.5, z, BALL_COLORS_R[name]]);
}
}
hitBall();
}
function hitBall()
{
movFin = false;
ABWorld.scene.addEventListener("update", function(){
if (movementFinished()){
calculateScore(YOURSCORE, OTHERSCORE, WHITE_POT, BLACK_POT);
//console.log("Score for this turn: " + SCORE + ".");
clearTable();
}
});
if (validSetUp() === true){
firstHit = true;
ANGLE = ballChoice();
if (WHITE != -1){
cue = makeCue(ANGLE);
WHITE.applyCentralForce(ANGLE);
removeCue(cue);
}
}
}
function clearTable()
{
while (BALLS.length !== 0){
LIMIT[BALL_COLORS_R[BALLS[0].name]] += 1;
BALLS[0].name = "None";
BALLS[0].geometry.dispose();
BALLS[0].material.dispose();
ABWorld.scene.remove(BALLS[0]);
BALLS.splice(0, 1);
}
reset();
}
function reset()
{
BALL_COUNT = 0;
WHITE_POT = false;
BLACK_POT = false;
YOURSCORE = 0;
OTHERSCORE = 0;
FOUL = false;
if (toggledBasic === true){
YOURCOLOR = "None";
basicSetUp();
}
else{
for (var i in BALL_LAYOUT){
var b = BALL_LAYOUT[i];
createBall(b[0], b[1], b[2], b[3]);
}
if (CALCULATING === true && BALLS_TO_POT > BALLS_ATTEMPTED){
hitBall();
}
else if (CALCULATING === true && BALLS_TO_POT == BALLS_ATTEMPTED){
CALCULATING = false;
CALCULATED = true;
console.log("Finished Calculations");
console.log("Best Scores: ", BEST_SCORES);
}
}
}
function calculateScore(x, y, w, b)
{
var score = 50;
if (b === true && (w === true || YOURCOLOR == "None" || LIMIT[BALL_COLORS_R[YOURCOLOR]] != 7)){
score = -1;
}
else if (b === true){
score = 100;
}
if ((FOUL === true || w === true) && y === 0){
score += (-8) + (x * 7);
}
else{
score += (-9 * y) + (x * 7);
}
if (BEST_SCORES.length < 3){
BEST_SCORES.push([score, ANGLE]);
}
else{
chooseBest(score, ANGLE);
}
console.log("Score for this turn: " + score + ".");
}
function chooseBest(s, a)
{
var min = 0;
for (var i in BEST_SCORES){
if (BEST_SCORES[i][0] < BEST_SCORES[min][0]){
min = i;
}
}
if (BEST_SCORES[min][0] < s){
BEST_SCORES[min] = [s, a];
}
}
function validSetUp()
{
if (LIMIT[2] + LIMIT[3] > 0){
console.log("Invalid Set Up! Black or white ball missing.");
return(false);
}
else if (YOURCOLOR == "None" && LIMIT[0] + LIMIT[1] + LIMIT[2] + LIMIT[3] > 0){
console.log("Invalid Set Up! Incorrect setting of your color, should be Yellow or Red.");
return(false);
}
else if ((YOURCOLOR == "Red" || YOURCOLOR == "Yellow") && LIMIT[0] + LIMIT[1] === 0){
console.log("Invalid Set Up! Incorrect setting of your color, should be None.");
return(false);
}
else{
return(true);
}
}
function colorCount(color)
{
var x = 0;
for (var i in BALLS){
if (BALLS[i].name == color){
x += 1;
}
}
return(x);
}
function makeCue(angle)
{
firstHit = true;
if (WHITE != -1){
//The Cue
var cue_material = Physijs.createMaterial(new THREE.MeshStandardMaterial({color : "#c96120"}));
var cue = new THREE.Mesh(new THREE.CylinderGeometry(0.5,1.5,100, 100), cue_material , 0);
var pivot = new THREE.Mesh(new THREE.SphereGeometry(0.001, 10, 10), cue_material, 0);
pivot.position.x = WHITE.position.x;
pivot.position.y = WHITE.position.y;
pivot.position.z = WHITE.position.z;
cue.position.x = -50;
cue.position.y = 5;
cue.rotation.z = (Math.PI / 2) * 3 - 0.05;
var rotate = Math.atan((angle.z - WHITE.position.z)/(angle.x - WHITE.position.x)) ;//+ (Math.PI/2);
console.log(rotate);
pivot.add(cue);
pivot.rotation.y = rotate ;//(angle.z/angle.x) * 3 - 0.05;
ABWorld.scene.add(pivot);
return pivot;
}
}
function waiting(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function removeCue(object){
await waiting(2000);
//console.log("Waited 2s");
object.geometry.dispose();
object.material.dispose();
ABWorld.scene.remove(object);
}
function isValid(ball){
if (YOURCOLOR == "None"){
if (ball.name == "Yellow" || ball.name == "Red"){
console.log("Valid Selection");
return(true);
}
}
else if (ball.name == YOURCOLOR){
console.log("Valid Selection");
return(true);
}
else if (ball.name == "Black" && LIMIT[BALL_COLORS_R[YOURCOLOR]] == 7){
return(true);
}
return(false);
}
function ballChoice()
{
// choose a valid ball to calculate angle
var valid_balls = 0;
for (var i in BALLS){
if (isValid(BALLS[i])){
if (valid_balls == BALLS_ATTEMPTED){
BALLS_ATTEMPTED += 1;
return(pickAngle(BALLS[i]));
}
valid_balls += 1;
}
}
}
function pickAngle(ball)
{
// calculate angle to hit ball
if (checkSpace(ball)){
var length = (Math.sqrt(Math.pow((WHITE.position.x - ball.position.x), 2) + Math.pow((WHITE.position.z - ball.position.z), 2)));
return(new THREE.Vector3 ((BASE_POWER * MIN_POWER * ((ball.position.x - WHITE.position.x) / length)), -100, (BASE_POWER * MIN_POWER * ((ball.position.z - WHITE.position.z) / length))));
}
}
function checkSpace(ball)
{
var x_material = Physijs.createMaterial(new THREE.MeshStandardMaterial({color : "#c96120"}));
var length = (Math.sqrt(Math.pow((WHITE.position.x - ball.position.x), 2) + Math.pow((WHITE.position.z - ball.position.z), 2))) - 4.5;
var x_geometry = new THREE.BoxGeometry(length, 1, 4);
var x = new Physijs.BoxMesh(x_geometry, x_material, 0.001);
x.position.x = (ball.position.x + WHITE.position.x) / 2;
x.position.y = p_height + 4;
x.position.z = (ball.position.z + WHITE.position.z) / 2;
ABWorld.scene.add(x);
x.geometry.dispose();
x.material.dispose();
ABWorld.scene.remove(x);
return(true);
}
function slowBall(ball)
{
var ang_v = ball.getAngularVelocity().length();
var ang_v_x = ball.getAngularVelocity().x;
var ang_v_z = ball.getAngularVelocity().z;
if (firstHit === false){
if (ang_v < 0.5){
ball.setAngularVelocity(new THREE.Vector3(0, 0, 0));
}
else{
//slow X
if (ang_v_x > -0.1 && ang_v_x < 0.1){
ball.setAngularVelocity(new THREE.Vector3(0,0, ang_v_z));
}
else if (ang_v_x >= 0.1) {
ball.setAngularVelocity(new THREE.Vector3((ang_v_x - SLOWFACTOR),0, ang_v_z));
}
else{
ball.setAngularVelocity(new THREE.Vector3((ang_v_x + SLOWFACTOR),0, ang_v_z));
}
//slow Z
if (ang_v_z > -0.1 && ang_v_z < 0.1){
ball.setAngularVelocity(new THREE.Vector3(ang_v_x, 0, 0));
}
else if (ang_v_z >= 0.1) {
ball.setAngularVelocity(new THREE.Vector3(ang_v_x, 0, (ang_v_z - SLOWFACTOR)));
}
else{
ball.setAngularVelocity(new THREE.Vector3(ang_v_x, 0, (ang_v_z + SLOWFACTOR)));
}
}
}
}
function movementFinished()
{
if (firstHit === false && movFin === false){
var vel = 0;
for (var x in BALLS){
vel += BALLS[x].getAngularVelocity().length();
}
if (vel < 0.2){
console.log("Movement Finished!");
movFin = true;
return(true);
}
return(false);
}
}
// ===================================================================================================================
// === Ball Creation =================================================================================================
// ===================================================================================================================
function basicSetUp()
{
if (BALL_COUNT === 0){
createBall(-30, p_height + 0.5, 0, 3); //white
createBall(30, p_height + 0.5, 0, 2); //black
createBall(23, p_height + 0.5, 0, 1); //red
createBall(26.5, p_height + 0.5, -2, 1); //red
createBall(30, p_height + 0.5, 4, 1); //red
createBall(33.5, p_height + 0.5, 2, 1); //red
createBall(33.5, p_height + 0.5, -6, 1); // red
createBall(37, p_height + 0.5, -4, 1); //red
createBall(37, p_height + 0.5, 8, 1); //red
createBall(26.5, p_height + 0.5, 2, 0); //yellow
createBall(30, p_height + 0.5, -4, 0); //yellow
createBall(33.5, p_height + 0.5, -2, 0); //yellow
createBall(33.5, p_height + 0.5, 6, 0); //yellow
createBall(37, p_height + 0.5, 0, 0); //yellow
createBall(37, p_height + 0.5, 4, 0); //yellow
createBall(37, p_height + 0.5, -8, 0); //yellow
}
if (CALCULATING === true && BALLS_TO_POT > BALLS_ATTEMPTED){
hitBall();
}
else if (CALCULATING === true && BALLS_TO_POT == BALLS_ATTEMPTED){
CALCULATING = false;
CALCULATED = true;
console.log("Finished Calculations");
console.log("Best Scores: ", BEST_SCORES);
}
}
function createBall(x, y, z, CURRENT_COLOR)
{
if ( resourcesLoaded && LIMIT[CURRENT_COLOR] !== 0 && splashClicked)
{
var ball;
if (CURRENT_COLOR === 0){
ball = new Physijs.SphereMesh(ball_geometry, ball_material_0, BALL_MASS);
}
else if (CURRENT_COLOR == 1){
ball = new Physijs.SphereMesh(ball_geometry, ball_material_1, BALL_MASS);
}
else if (CURRENT_COLOR == 2){
ball = new Physijs.SphereMesh(ball_geometry, ball_material_2, BALL_MASS);
}
else{
ball = new Physijs.SphereMesh(ball_geometry, ball_material_3, BALL_MASS);
}
ball.name = BALL_COLORS[CURRENT_COLOR];
ball.collisions = 0;
ball.castShadow = true;
//ball.position.set(1, 40, 1);
ball.position.set(x, y + 2, z);
var slowing = true;
ABWorld.scene.addEventListener("update", function(){
if (ball.name != "None"){
slowBall(ball);
}
});
ball.addEventListener('collision', function(other_object, relative_velocity, relative_rotation, contact_normal)
{
if (ball == WHITE && other_object != GROUND){
if (firstHit === true){
if(other_object.name == YOURCOLOR || YOURCOLOR == "None"){
console.log("Valid Hit");
}
else if (LIMIT[BALL_COLORS_R[YOURCOLOR]] == 7 && other_object.name == "Black"){
console.log("Valid Hit");
}
else{
console.log("Invalid Hit");
FOUL = true;
}
firstHit = false;
}
}
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.push(ball);
if (CURRENT_COLOR == 3){
WHITE = ball;
}
BALL_COUNT += 1;
ABWorld.scene.add(ball);
LIMIT[CURRENT_COLOR] -= 1;
}
}
function removeBall(ball)
{
var index = BALLS.indexOf(ball);
if (index > -1) {
BALLS.splice(index, 1);
}
if (ball.name == YOURCOLOR){
console.log("Good Shot!");
YOURSCORE += 1;
}
else if (YOURCOLOR == "None" && (ball.name !== "Black" && ball.name !== "White")){
console.log("You are now " + ball.name + "s.");
YOURCOLOR = ball.name;
YOURSCORE += 1;
}
else if (ball.name == "Black"){
BLACK_POT = true;
}
else if (ball.name == "White"){
WHITE_POT = true;
console.log("Foul Shot.");
}
else{
console.log("Bad Shot :(");
OTHERSCORE += 1;
}
LIMIT[BALL_COLORS_R[ball.name]] += 1;
ball.name = "None";
ball.geometry.dispose();
ball.material.dispose();
ABWorld.scene.remove(ball);
}
// ===================================================================================================================
// === Keyboard & Mouse Control ======================================================================================
// ===================================================================================================================
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, BALL_CHOICE);}
}
//for future drag functionality
function initTouch (event)
{
console.log(event);
var object = (ABWorld.hitsObjectPoint(x, y, GROUND)); // returns null if no hit
if (object !== null){
createBall(object.x, object.y, object.z, BALL_CHOICE);}
}
// ===================================================================================================================
// === User Interface ================================================================================================
// ===================================================================================================================
function initPreOptions()
{
$("#user_span1").html("<p align=\"center\">Page: <b>"+ PAGE_SELECT + "</b></p>");
$("#user_span2").html("<p align=\"center\"><button id='page1'>Page 1</button> <button id='page2'>Page 2</button> <button id='page3'>Page 3</button></p>");
$("#user_span4").html(line4_1);
$("#user_span6").html(line6_1);
s = "<p align=\"center\"><button id='calculateShot'>GO!</button></p>";
$("#user_span10").html(s);
$(document).ready(function(){
//Html css
//$("html").css("background-color", "green");
//Button Functionality
$("#page1").click(function(){pageChange(1);});
$("#page2").click(function(){pageChange(2);});
$("#page3").click(function(){pageChange(3);});
$("#calculateShot").click(function(){calculateShot();});
//Button CSS
$("#page1").css("background-color", "#99ff33");
$("#page2").css("background-color", "#99ff33");
$("#page3").css("background-color", "#99ff33");
$("#calculateShot").css("background-color", "#99ff33");
});
}
function initPostOptions()
{
//$("#user_span1").html("<p align=\"center\">The Colour you are playing as is set to: <b>" + YOURCOLOR + "</b></p>");
$("#user_span2").html("<p align=\"center\">The Table is being <b>Calculated</b></p>");
//$("#user_span3").html("<p align=\"center\"></p>");
$("#user_span4").html("<p align=\"center\">The Camera Settings :</p>");
$("#user_span5").html(line6_3);
//$("#user_span6").html("<p align=\"center\">FIN</p>");
$("#user_span10").html("<p></p>");
$(document).ready(function(){
//Button Functionality
$("#cameraFlatButton").click(function(){cameraFlatDown();});
$("#cameraCornerButton").click(function(){cameraSomeCornerPocket();});
//Button CSS
$("#cameraFlatButton").css({"background-color" : "#668cff" , "color" : "white"});
$("#cameraCornerButton").css({"background-color" : "#c68c53" , "color" : "white"});
});
}
function updatePreHUD()
{
$("#user_span1").html("<p align=\"center\">Page: <b>"+ PAGE_SELECT + "</b></p>");
if (PAGE_SELECT == 1){
$("#user_span3").html("<p align=\"center\">Ball Selected: <b>"+ BALL_TYPE[BALL_CHOICE] + "</b></p>");
$("#user_span5").html("<p align=\"center\">The Colour you are playing as is set to: <b>" + YOURCOLOR + "</b></p>");
if (CURRENT_PAGE !== PAGE_SELECT){
$("#user_span4").html(line4_1);
$("#user_span6").html(line6_1);
$(document).ready(function(){
//Button Functionality
$("#yellowButton").click(function(){selectBall(0);});
$("#redButton").click(function(){selectBall(1);});
$("#blackButton").click(function(){selectBall(2);});
$("#whiteButton").click(function(){selectBall(3);});
$("#yourNButton").click(function(){setDifficulty(setColor("None"));});
$("#yourYButton").click(function(){setDifficulty(setColor("Yellow"));});
$("#yourRButton").click(function(){setDifficulty(setColor("Red"));});
//Button CSS
$("#yellowButton").css("background-color", "yellow");
$("#redButton").css({"background-color" : "red" , "color" : "white"});
$("#blackButton").css({"background-color" : "black" , "color" : "white"});
$("#whiteButton").css("background-color", "white");
$("#yourNButton").css({"background-color" : "grey" , "color" : "white"});
$("#yourYButton").css("background-color", "yellow");
$("#yourRButton").css({"background-color" : "red" , "color" : "white"});
});
}
}
else if (PAGE_SELECT == 2){
$("#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>");
if (CURRENT_PAGE !== PAGE_SELECT){
$("#user_span4").html(line4_2);
$("#user_span6").html(line6_2);
$(document).ready(function(){
//Button Functionality
$("#decreaseFrictionButton").click(function(){decreaseFriction();});
$("#increaseFrictionButton").click(function(){increaseFriction();});
$("#decreasePowerMinButton").click(function(){decreasePowerMin();});
$("#increasePowerMinButton").click(function(){increasePowerMin();});
$("#decreasePowerMaxButton").click(function(){decreasePowerMax();});
$("#increasePowerMaxButton").click(function(){increasePowerMax();});
//Button CSS
$("#decreaseFrictionButton").css({"background-color" : "red" , "color" : "white"});
$("#increaseFrictionButton").css("background-color", "#00ff00");
$("#decreasePowerMinButton").css({"background-color" : "black" , "color" : "white"});
$("#increasePowerMinButton").css({"background-color" : "black" , "color" : "white"});
$("#decreasePowerMaxButton").css({"background-color" : "black" , "color" : "white"});
$("#increasePowerMaxButton").css({"background-color" : "black" , "color" : "white"});
});
}
}
else {
$("#user_span3").html("<p align=\"center\">The Difficultly is set to: <b>" + difficulty + "</b></p>");
$("#user_span5").html("<p align=\"center\">The Camera Settings :</p>");
if (CURRENT_PAGE !== PAGE_SELECT){
$("#user_span4").html(line4_3);
$("#user_span6").html(line6_3);
$(document).ready(function(){
//Button Functionality
$("#easyButton").click(function(){setDifficulty("Easy");});
$("#mediumButton").click(function(){setDifficulty("Medium");});
$("#hardButton").click(function(){setDifficulty("Hard");});
$("#cameraFlatButton").click(function(){cameraFlatDown();});
$("#cameraCornerButton").click(function(){cameraSomeCornerPocket();});
//Button CSS
$("#easyButton").css("background-color", "#00ff00");
$("#mediumButton").css("background-color", "yellow");
$("#hardButton").css({"background-color" : "red" , "color" : "white"});
$("#cameraFlatButton").css({"background-color" : "#668cff" , "color" : "white"});
$("#cameraCornerButton").css({"background-color" : "#c68c53" , "color" : "white"});
});
}
}
CURRENT_PAGE = PAGE_SELECT;
}
function updatePostHUD(){
$("#user_span1").html("<p align=\"center\">The Colour you are playing as is set to: <b>" + YOURCOLOR + "</b></p>");
$("#user_span3").html("<p align=\"center\">The White Balls Coordinates <b>"+parseInt(WHITE.position.x) +"x "+ parseInt(WHITE.position.y)+"y "+parseInt(WHITE.position.z)+"z </b></p>");
$("#user_span6").html("<p align=\"center\">The Amount of Balls on the table <b>" + BALLS.length + "</b></p>");
}
// ===================================================================================================================
// === Ancient Brain Functions =======================================================================================
// ===================================================================================================================
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.ontouchstart = initTouch;
//ABHandler.initMouseDrag = initDrag;
//ABHandler.mouseDrag = drag
};
this.nextStep = function() // not used
{
if (splashClicked === true && toggleBasic === true){
basicSetUp();
toggleBasic = false;
toggledBasic = true;
}
if (CALCULATED === false){
updatePreHUD();}
//else if (CALCULATING === true){
//}
else{
if (counter < 1){
console.log("post HUD");
initPostOptions();
counter++;
}
console.log("Update post HUD");
updatePostHUD();
}
};
}
// --- Splash screen --------------------------------------------------------------
AB.newSplash ("<p>Optional Start Settings</p><p align=\"center\"><button id='basicSetUp1'>Initial arrangment</button></p>");
$(document).ready(function(){
//Button Functionality
$("#basicSetUp1").click(function(){toggleBasic = true;});
//Button CSS
$("#basicSetUp1").css({"background-color" : "black" , "color" : "white" , "padding" : "15px 30px", "font-size" : "16px"});
});
//document.
// when user clicks/touches button on splash screen, audio starts and run starts:
$("#splashbutton").click (function()
{
AB.removeSplash(); // remove splash screen
splashClicked = true;
});