// Cloned by Alexandru on 1 Dec 2022 from World "Castle World" by Starter user
// Please leave this clone trail here.
// ==== Starter World =================================================================================================
// This code is designed for use on the Ancient Brain site.
// This code may be freely copied and edited by anyone on the Ancient Brain site.
// To include a working run of this program on another site, see the "Embed code" links provided on Ancient Brain.
// ====================================================================================================================
// Demo of 3D model
// OBJ plus MTL
// A "Simple World" like chase inside an invisible arena inside the castle
// Chase uses x,y,z rather than grid of squares
// ===================================================================================================================
// === 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.clockTick = 100;
// Speed of run: Step every n milliseconds.
AB.maxSteps = 500;
// Length of run: Maximum length of run in steps.
AB.screenshotStep = 50;
// Take screenshot on this step. (All resources should have finished loading.)
//---- global constants: -------------------------------------------------------
const OBJPATH = "/uploads/starter/"; // path of OBJ and MTL
const OBJNAME = "castle.obj";
const MTLNAME = "castle.new.mtl";
// castle credit
// https://www.script-tutorials.com/webgl-with-three-js-lesson-6/
// http://www.script-tutorials.com/demos/409/index2.html
// =================================================================================
// Bug: Original MTL file fails with new Three.js
// The original "castle.mtl" works with old Three.js but fails with new version.
// Solution: Edit the MTL file. See note here:
// https://ancientbrain.com/docs.three.php
// =================================================================================
const TEXTURE_AGENT = '/uploads/starter/pacman.jpg' ;
const TEXTURE_ENEMY = '/uploads/starter/ghost.3.png' ;
// credits:
// https://commons.wikimedia.org/wiki/Category:Pac-Man_icons
// https://commons.wikimedia.org/wiki/Category:Skull_and_crossbone_icons
const MUSIC_BACK = '/uploads/starter/Defense.Line.mp3' ;
const SKYCOLOR = 0xffffcc ; // a number, not a string
const LIGHTCOLOR = 0xffffff ;
const squaresize = 50; // size of cube length
// basic castle model size
// see debug line to compute model size below
// Xsize: 6158.792236328125 Ysize: 703.5784759521484 Zsize: 3791.05908203125
const MODELLENGTH = 6159;
const MODELWIDTH = 3791;
const SCALE_CASTLE = 0.5; // scale it by this
const SCALEDMODELLENGTH = MODELLENGTH * SCALE_CASTLE;
const SCALEDMODELWIDTH = MODELWIDTH * SCALE_CASTLE;
const startRadiusConst = SCALEDMODELLENGTH * 0.5 ;
const maxRadiusConst = SCALEDMODELLENGTH * 10 ;
// camera points at 0,0
// where to put castle?
// fit bottom LHS corner to here:
const CX = - ( SCALEDMODELLENGTH * 0.3 );
const CZ = ( SCALEDMODELWIDTH * 0.3 );
// how far can the agent and enemy wander inside the castle
// experiment to see where the inner box fits inside the model
const MIN_X = CX + ( SCALEDMODELLENGTH * 0.1 ) ;
const MAX_X = CX + ( SCALEDMODELLENGTH * 0.55 ) ;
const MIN_Z = CZ - ( SCALEDMODELWIDTH * 0.45 ) ;
const MAX_Z = CZ - ( SCALEDMODELWIDTH * 0.1 ) ;
//--- change ABWorld defaults: -------------------------------
ABHandler.GROUNDZERO = true; // "ground" exists at altitude zero
ABWorld.drawCameraControls = false;
var thecastle
function loadResources() // asynchronous file loads - call initScene when finished
{
// load castle model OBJ and materials MTL (which reference JPEGs)
var m = new THREE.MTLLoader();
m.setResourcePath ( 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 )
{
thecastle = object;
if ( asynchFinished() ) initScene();
});
});
// load cube textures
var loader1 = new THREE.TextureLoader();
var loader2 = new THREE.TextureLoader();
loader1.load ( TEXTURE_AGENT, function ( thetexture )
{
thetexture.minFilter = THREE.LinearFilter;
agent_texture = thetexture;
if ( asynchFinished() ) initScene();
});
loader2.load ( TEXTURE_ENEMY, function ( thetexture )
{
thetexture.minFilter = THREE.LinearFilter;
enemy_texture = thetexture;
if ( asynchFinished() ) initScene();
});
}
function asynchFinished()
{
if ( thecastle ) return true;
else return false;
}
function initScene() // file loads have returned
{
// add castle object to scene
thecastle.scale.multiplyScalar ( SCALE_CASTLE );
thecastle.position.y = - (squaresize * 0.5); // adjust so cubes (centred on 0) appear exactly above castle floor
thecastle.position.x = CX;
thecastle.position.z = CZ;
ABWorld.scene.add ( thecastle );
// calculate OBJ object size:
// console.log ( "Xsize: " + ABWorld.objectXsize(thecastle) + " Ysize: " + ABWorld.objectYsize(thecastle) + " Zsize: " + ABWorld.objectZsize(thecastle) );
// ready to start run loop?
ABWorld.render();
console.log ( "Resources loaded." );
resourcesLoaded = true;
if ( resourcesLoaded && splashClicked )
AB.runReady = true; // start run loop
}
AB.world.newRun = function()
{
ABWorld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR );
// newRun can run behind splash screen
// do not start run loop until resources ready AND splash screen is dismissed
AB.runReady = false;
loadResources(); // aynch file loads
// calls initScene() when it returns
var thelight = new THREE.DirectionalLight ( LIGHTCOLOR, 5 );
thelight.position.set ( startRadiusConst, startRadiusConst, startRadiusConst );
ABWorld.scene.add(thelight);
};
// --- Splash screen --------------------------------------------------------------
// Splash screen is to get audio started on mobile/Chrome by user interaction.
// This should works on all platforms - plays background music.
// display standard splash screen (World title, World image, Start button)
AB.newSplash();
// when user clicks/touches button on splash screen, audio starts and run starts:
AB.splashClick ( function ()
{
// audio linked to user interaction:
AB.backgroundMusic ( MUSIC_BACK );
AB.removeSplash(); // remove splash screen
// ready to start run loop?
splashClicked = true;
if ( resourcesLoaded && splashClicked )
AB.runReady = true; // start run loop
});