// Cloned by Xiaoyu Lyu on 28 Nov 2022 from World "New World" by Niall Kelly
// Please leave this clone trail here.
var start_r = 100 //camera start pos
var max_r = 300 // Max render distance
var p1score = 0;
var p2score = 0;
var max_targets = 3;
var alltargets = new Array(0); // array of all targets currently in play
const mixers = [];
const animClock = new THREE.Clock();
const birdClock = new THREE.Clock();
const gameClock = new THREE.Clock();
var bird;
var hitbox;
var dir;
const SKYBOX_ARRAY = [
"/uploads/kellyn88/sbleft.jpg", // left
"/uploads/kellyn88/sbr.png", // right
"/uploads/kellyn88/test.png",
"/uploads/kellyn88/skybox_base.png", //base
"/uploads/kellyn88/test.png",
"/uploads/kellyn88/test.png"
];
var gridSetup = [
[-160, -100, 70], [-80, -100, 70], [0, -100, 70], [80, -100, 70], [160, -100, 70],
[-160, -100, -10], [-80, -100, -10], [0, -100, -10], [80, -100, -10], [160, -100, -10], // Layout of poosible target spawn positions
[-160, -100, -90], [-80, -100, -90], [0, -100, -90], [80, -100, -90], [160, -100, -90]
]
// !!!BACKGROUND SOUND UNCOMMENT WHEN DONE!!!
// const MUSICFILE = '/uploads/kellyn88/ambience.mp3';
// AB.backgroundMusic ( MUSICFILE );
const shoot_short = "uploads/kellyn88/shoot_short.wav";
const shoot_long = "uploads/kellyn88/shoot_long.wav";
const squak = "uploads/kellyn88/eagle_call.wav";
AB.newSplash ( splashScreenStart() );
AB.world.newRun = function()
{
if (AB.onMobile()){
start_r = 500;
max_r = 1000;
loadBird();
}
AB.socketStart();
initScene();
AB.runReady = false;
cameraControls();
//var buttons = " <p> <button onclick='readyUp();' class='ab-normbutton mybutton' >Ready </button> </p> ";
// AB.msg ( buttons, 3 );
};
// function readyUp(){
// AB.runReady = true;
// }
function initScene(){
AB.headerWidth(335);
var color = new THREE.Color();
ABWorld.init2d ( start_r, max_r, color );
ABWorld.scene.background = new THREE.CubeTextureLoader().load ( SKYBOX_ARRAY ); // Initiate scene
var light = new THREE.AmbientLight("white", 0.8);
ABWorld.scene.add(light);
};
AB.world.nextStep = function()
{
if(Math.trunc(gameClock.getElapsedTime()) == 60){
AB.abortRun = true;
}
if (alltargets.length < max_targets){ // Spawn targets
spawnTarget();
}
if(AB.socket){
if(AB.socket.connected){
AB.socketOut(p1score)
AB.msg("P1 Score = " + p1score + " P2 score = " + p2score + "\n Time remaining: " + Math.trunc(60 - gameClock.getElapsedTime()) ); // Display player scores
}
}
if(bird){
if(bird.position.x == 25 || bird.position.x == -25){
for (var i = 0; i < alltargets.length; i++){
if (alltargets[i].name == "bird"){
alltargets.splice(i, 1);
}
}
ABWorld.scene.remove(bird) && ABWorld.scene.remove(hitbox); // If bird has left the screen remove it
bird = null;
max_targets = 3;
}
else{
anim_bird();
bird.translateY(-0.5) && hitbox.translateX(dir); // Move bird
}
}
else{
var t = birdClock.getElapsedTime();
if (t >= 15){
var randomIndex = AB.randomIntAtoB(1, 50); // Bird has a 1/50 chance of spawning once 20 seconds from the last bird spawn has elapsed
if(randomIndex == 25){
loadBird();
birdClock.start();
}
}
}
};
function spawnTarget(){
var texture = new THREE.TextureLoader().load("/uploads/kellyn88/target.png");
var shape = new THREE.CylinderGeometry(30, 30, 5, 32);
var cover = new THREE.MeshBasicMaterial({map: texture});
var target = new THREE.Mesh(shape, cover); // Create target mesh
var randomIndex = AB.randomIntAtoB(0, gridSetup.length);
var item = gridSetup[randomIndex];
target.position.set(item[0], item[1], item[2]); // Select Random spawn location
ABWorld.scene.add(target); // Add target to scene
gridSetup.splice(randomIndex, 1); // Grid position is now occupied
alltargets.push(target); // Add to list of targets
}
function cameraControls()
{
ABHandler.initTouchDrag = mouseClick; // Override default mobile controls
ABHandler.touchDrag = mouseDrag;
ABHandler.touchZoom = mouseZoom;
ABHandler.initMouseDrag = mouseClick; // Override default desktop controls
ABHandler.mouseDrag = mouseDrag;
ABHandler.mouseZoom = mouseZoom;
}
function mouseClick(x, y) //Check if mouse click hits target
{
audioHandler("shoot");
targetHit(x, y);
return;
}
function mouseDrag(x, y){ // Disable drag
return;
}
function mouseZoom(x){ // Disable zoom
return;
}
function targetHit(x, y) // Go through list of targets and check if any are hit by mouse click
{
if(alltargets.length > 0){
for (var i = 0; i < alltargets.length; i++){
var target = alltargets[i];
if ( ABWorld.hitsObject ( x, y, target )){
if (target.name != "bird"){
var pos = [target.position.x, target.position.y, target.position.z];
gridSetup.push(pos); // Grid pos is free again
ABWorld.scene.remove(target); // Remove target from scene
alltargets.splice(i, 1); // Remove from list of all targets
p1score++; // Increase score
}
else{
console.log("bird hit");
ABWorld.scene.remove(bird) && ABWorld.scene.remove(target);
bird = null;
alltargets.splice(i, 1);
max_targets = 3;
p1score = p1score + 10;
}
break;
}
}
}
return;
}
function audioHandler(instance){ // Function to play audio
var a;
if (instance == "shoot"){
a = new Audio( shoot_short );
a.play();
}
else if(instance == "bird"){
a = new Audio( squak );
a.play();
}
}
function loadBird() // Function decides bird's orientation and spawn location and spawns in the object
{
var xIndex;
var zIndex = AB.randomIntAtoB(-5, 5)
var rotation = new Array (0);
ran = AB.randomIntAtoB(0, 1);
if (ran === 0){
dir = -0.5
rotation = [0, Math.PI, Math.PI / 2];
xIndex = 20;
}
else{
dir = 0.5
rotation = [Math.PI, 0, Math.PI / 2];
xIndex = -20;
}
const loader = new THREE.GLTFLoader();
const onLoad = ( gltf, position ) =>
{
const model = gltf.scene.children[ 0 ];
model.position.copy( position );
const animation = gltf.animations[ 0 ];
const mixer = new THREE.AnimationMixer( model );
mixers.push( mixer );
const action = mixer.clipAction( animation );
action.play()
model.rotation.set( rotation[0], rotation[1], rotation[2]);
loadHitbox(position);
ABWorld.scene.add( model );
bird = model;
};
const birdpos = new THREE.Vector3 (xIndex, (start_r - (start_r * 0.1)), zIndex);
// can load 3D models of other user:
audioHandler("bird");
loader.load ( '/uploads/kellyn88/simple_bird.glb', gltf => onLoad ( gltf, birdpos ) );
}
function loadHitbox(pos){
var shape = new THREE.BoxGeometry(2, 2, 0.7);
var cover = new THREE.MeshBasicMaterial(0xfff); // Create mesh of hitbox for bird
var target = new THREE.Mesh(shape, cover);
max_targets = 4;
target.visible = false;
target.name = "bird";
target.position.set(pos.x, pos.y, pos.z - 0.1);
ABWorld.scene.add(target);
hitbox = target;
alltargets.push(target);
console.log (alltargets);
}
function anim_bird(){
const delta = animClock.getDelta();
mixers.forEach( ( mixer ) => { mixer.update( delta ); } ); // Initiate bird flying animation
}
AB.world.endRun = function()
{
AB.newSplash ( splashScreenEnd() );
};
function splashScreenStart() // HTML format string of instructions for splash screen
{
var s = "Shoot targets as they appear to earn points.\n\n";
if ( AB.onDesktop() ) s = s + " Desktop instructions: Use your mouse to aim and click to shoot.\n\n" ;
else s = s + " Mobile instructions: Tap to shoot.\n\n" ;
s = s + "1 point is awarded for each target destroyed. Keep an eye out for Hawks. They are more difficult to hit but are worth 10 points. Earn more points than your opponent to win!";
return ( s );
}
function splashScreenEnd() // HTML format string of instructions for splash screen
{
var s = "Game Over!\n\n";
if (p1score > p2score){
s = s + "p1 won with a score of " + p1score
}
else if (p1score < p2score){
s = s + "p1 won with a score of " + p1score
}
else if (p1score == p2score){
s = s + "Draw! Both players had a score of " + p1score
}
s = s + " Your score: " + p1score
return ( s );
}
AB.splashClick ( function ()
{
AB.runReady = true;
AB.removeSplash(); // remove splash screen
});
AB.socketIn = function (s){
p2score = s // Socket functionality (p2 score)
}
// AB.socketUserlist = function ( array ) {
// console.log(array.length);
// };