// Cloned by issafae2 on 4 Dec 2022 from World "User-controlled Model 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.// ====================================================================================================================// User controlled (not Mind controlled) 3D model World with various features:// - User controlled UP/LEFT/RIGHT arrows move model // - "First Person View" - Camera rotates with direction you are facing// Best effect is with "Move with" camera// - Can have one or multiple skeletons chasing you // Smooth movement// UP moves forward in whatever angle you are at// LEFT/RIGHT rotate by small angle// Uses x,y,z rather than grid of squares // Has collision detection for skeleton moves// Things to do: // - Initialise skeletons so they are not already colliding // - Collision detection for agent moves// ===================================================================================================================// === 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. Default 100.
AB.maxSteps =10000;// Length of run: Maximum length of run in steps. Default 1000.
AB.screenshotStep =100;// Take screenshot on this step. (All resources should have finished loading.) Default 50.
AB.drawRunControls =false;// Scrap the Run/Step/Pause controls//---- global constants: -------------------------------------------------------// number of skeletons: // const NO_SKELETONS = 1;const NO_SKELETONS =50;const OBJ_SKELETON ='/uploads/starter/skelet.obj';// skeleton credit// formerly here:// http://tf3dm.com/3d-model/skeleton-with-organs-91102.htmlconst OBJPATH ="/uploads/starter/";// path of OBJ and MTL (Peter Parker model)const OBJNAME ="Peter_Parker.obj";const MTLNAME ="Peter_Parker.mtl";// Peter Parker credit// formerly here:// https://free3d.com/3d-model/spider-man-4998.html// multiply model sizes by some amount:const SCALE_HERO =70;// random size skeleton with each run: const SCALE_SKELETON = AB.randomFloatAtoB (1,6);// const SCALE_SKELETON = 4;const TEXTURE_SKELETON ='/uploads/starter/ghost.3.png';// credits:// https://commons.wikimedia.org/wiki/Category:Skull_and_crossbone_iconsconst MUSIC_BACK ='/uploads/starter/SuspenseStrings.mp3';// music credit// http://www.dl-sounds.com/royalty-free/suspense-strings/const MAXPOS =3500;// length of one side of the arena const SKYCOLOR =0xffffcc;// a number, not a string const LIGHTCOLOR =0xffffff;const startRadiusConst = MAXPOS ;// distance from centre to start the camera atconst maxRadiusConst = MAXPOS *10;// maximum distance from camera we will render things // how much agent moves each step const AGENT_STEP =100;// how much enemy moves each step const ENEMY_STEP =50;// this is as close as models come to other models const CLOSE_LIMIT =100;//--- lookat and follow -----------------------------------------------------------------// camera on "Move With" should move up/down in y axis as we re-scale objects// to place the follow camera just above the agent, something like: const FOLLOW_Y = SCALE_HERO *4;// going high up (or forward/back) means we get it out of agent's hair // to point the camera at skeleton's face, something like: const LOOKAT_Y = SCALE_SKELETON *40;// const CAMERASHIFT = 0 ; // put camera exactly inside agent's head// const CAMERASHIFT = SCALE_HERO * 2 ; // shift camera ahead of agent along line of sight const CAMERASHIFT =- SCALE_HERO *2;// shift camera behind agent, looking past agent along line of sight //--- change ABWorld defaults: -------------------------------ABHandler.MAXCAMERAPOS = maxRadiusConst ;ABHandler.GROUNDZERO =true;// "ground" exists at altitude zero// --- Rotations -----------------------// rotate by some amount of radians from the normal position // default is 0 which has the model facing DOWN (towards increasing z value) as far as the initial camera seesconst ROTATE_AMOUNT =Math.PI /20;// rotate amount in radians (PI = 180 degrees)//--- skybox: -------------------------------// urban photographic skyboxes, credit:// http://opengameart.org/content/urban-skyboxesconst SKYBOX_ARRAY =["/uploads/starter/posx.jpg","/uploads/starter/negx.jpg","/uploads/starter/posy.jpg","/uploads/starter/negy.jpg","/uploads/starter/posz.jpg","/uploads/starter/negz.jpg"];/*
// space skybox, credit:
// http://en.spaceengine.org/forum/21-514-1
const SKYBOX_ARRAY = [
"/uploads/starter/sky_pos_z.jpg",
"/uploads/starter/sky_neg_z.jpg",
"/uploads/starter/sky_pos_y.jpg",
"/uploads/starter/sky_neg_y.jpg",
"/uploads/starter/sky_pos_x.jpg",
"/uploads/starter/sky_neg_x.jpg"
];
*/// ===================================================================================================================// === End of tweaker's box ==========================================================================================// ===================================================================================================================// You will need to be some sort of JavaScript programmer to change things below the tweaker's box.var THESKELETONS =newArray( NO_SKELETONS );var theagent, theenemy;var agentRotation =0;var enemyRotation =0;var skeleton_texture;function loadResources()// asynchronous file loads - call initScene() when all finished {// load skeleton - OBJ that we will paint with a texture var loader =new THREE.OBJLoader(new THREE.LoadingManager());
loader.load ( OBJ_SKELETON,function( object ){
theenemy = object;// canonical enemy object - may be copied multiple times if( asynchFinished()) initScene();});// load Peter Parker model - OBJ plus MTL (plus TGA files) // old code:// THREE.Loader.Handlers.add ( /.tga$/i, new THREE.TGALoader() );
THREE.DefaultLoadingManager.addHandler (/\.tga$/i,new THREE.TGALoader());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 ){
theagent = object;if( asynchFinished()) initScene();});});// load textures var loader2 =new THREE.TextureLoader();
loader2.load ( TEXTURE_SKELETON,function( thetexture ){
thetexture.minFilter = THREE.LinearFilter;
skeleton_texture = thetexture;if( asynchFinished()) initScene();});}function asynchFinished()// all file loads returned {if( skeleton_texture && theenemy && theagent )returntrue;elsereturnfalse;}function initScene()// all file loads have returned {// add agent model // start at center
theagent.position.y =0;
theagent.position.x =0;
theagent.position.z =0;
theagent.scale.multiplyScalar ( SCALE_HERO );// scale it ABWorld.scene.add( theagent );// set up lookat and follow in direction agent is pointing in
setLookatFollow();// add enemies// first paint and size the canonical enemy object
theenemy.traverse (function( child ){if( child instanceof THREE.Mesh)
child.material.map = skeleton_texture ;});
theenemy.scale.multiplyScalar ( SCALE_SKELETON );// scale it // add perhaps multiple enemy models, starting near outside of arenafor(var i =0; i < NO_SKELETONS ; i++){var object = theenemy.clone();// copy the object multiple times
object.position.y =0;
object.position.x = AB.randomPick ( AB.randomIntAtoB (-MAXPOS/2,-MAXPOS/3), AB.randomIntAtoB ( MAXPOS/3, MAXPOS/2));
object.position.z = AB.randomPick ( AB.randomIntAtoB (-MAXPOS/2,-MAXPOS/3), AB.randomIntAtoB ( MAXPOS/3, MAXPOS/2));ABWorld.scene.add( object );// save in array for later
THESKELETONS[i]= object;}// finally skybox ABWorld.scene.background =new THREE.CubeTextureLoader().load ( SKYBOX_ARRAY,function(){ABWorld.render();
AB.removeLoading();
AB.runReady =true;});}// --- lookat and follow -----------------------------------// we do NOT automatically look at enemy / enemies // instead we look in direction we are facingfunction setLookatFollow()// set up lookat and follow {// follow - camera position // start with agent centre, then adjust it by small amount ABWorld.follow.copy ( theagent.position );ABWorld.follow.y = FOLLOW_Y ;// shifted forward/back along line linking agent with direction it is facing ABWorld.follow.x =ABWorld.follow.x +( CAMERASHIFT *Math.sin(agentRotation));ABWorld.follow.z =ABWorld.follow.z +( CAMERASHIFT *Math.cos(agentRotation));// lookat - look at point in distance along line we are facing// start with agent centre, then adjust it along line by huge amount ABWorld.lookat.copy ( theagent.position );ABWorld.lookat.y = LOOKAT_Y ;ABWorld.lookat.x =ABWorld.lookat.x +((startRadiusConst *3)*Math.sin(agentRotation));ABWorld.lookat.z =ABWorld.lookat.z +((startRadiusConst *3)*Math.cos(agentRotation));}// --- enemy move -----------------------------------// angle between two points (x1,y1) and (x2,y2)function angleTwoPoints ( x1, y1, x2, y2 ){returnMath.atan2 ( x2 - x1, y2 - y1 );}function dist ( a, b )// distance between them when a,b are Three vectors {return( a.distanceTo ( b ));}function collision ( proposedMove, k )// proposed move FOR skeleton k{if( dist ( proposedMove, theagent.position )< CLOSE_LIMIT )returntrue;for(var i=0; i < NO_SKELETONS ; i++)if( i != k )if( dist ( proposedMove, THESKELETONS[i].position )< CLOSE_LIMIT )returntrue;// else returnfalse;}function moveEnemy(){for(var i =0; i < NO_SKELETONS ; i++){var e = THESKELETONS[i];// rotate enemy to face agent
enemyRotation = angleTwoPoints ( e.position.x, e.position.z, theagent.position.x, theagent.position.z );
e.rotation.set(0, enemyRotation,0);// move along that line, if no collision with any other model var proposedMove =new THREE.Vector3(
e.position.x +( ENEMY_STEP *Math.sin(enemyRotation)),
e.position.y,
e.position.z +( ENEMY_STEP *Math.cos(enemyRotation)));if(! collision ( proposedMove, i ))
e.position.copy ( proposedMove );// else enemy i just misses a turn }}//--- key control of agent -------------------------------------------------------------const KEY_UP =38;const KEY_LEFT =37;const KEY_RIGHT =39;var OURKEYS =[ KEY_UP, KEY_LEFT, KEY_RIGHT ];function ourKeys ( event ){return( OURKEYS.includes ( event.keyCode ));}// UP moves forward in whatever angle you are at// LEFT/RIGHT rotate by small anglefunction keyHandler ( event ){if(! AB.runReady )returntrue;// not ready yet // if not handling this key, send it to default: if(! ourKeys ( event ))returntrue;// else handle it and prevent default:if( event.keyCode == KEY_UP )// move a bit along angle we are facing{
theagent.position.x = theagent.position.x +( AGENT_STEP *Math.sin(agentRotation));
theagent.position.z = theagent.position.z +( AGENT_STEP *Math.cos(agentRotation));}if( event.keyCode == KEY_LEFT )// rotate in place {
agentRotation = agentRotation + ROTATE_AMOUNT;
theagent.rotation.set(0, agentRotation,0);}if( event.keyCode == KEY_RIGHT ){
agentRotation = agentRotation - ROTATE_AMOUNT;
theagent.rotation.set(0, agentRotation,0);}// lookat/follow depend on change in agent position/rotation:
setLookatFollow();
event.stopPropagation(); event.preventDefault();returnfalse;}
AB.world.newRun =function(){
AB.loadingScreen();
AB.runReady =false;ABWorld.init3d ( startRadiusConst, maxRadiusConst, SKYCOLOR );
loadResources();// aynch file loads // calls initScene() when it returns // lightvar ambient =new THREE.AmbientLight();ABWorld.scene.add( ambient );var thelight =new THREE.DirectionalLight( LIGHTCOLOR,3);
thelight.position.set( startRadiusConst, startRadiusConst, startRadiusConst );ABWorld.scene.add(thelight);
document.onkeydown = keyHandler;};
AB.world.nextStep =function(){
moveEnemy();// enemies moves on their own clock };
AB.backgroundMusic ( MUSIC_BACK );