// Cloned by Raj Vibhute on 9 Nov 2022 from World "Complex 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.
// ====================================================================================================================
AB.clockTick = 100; // 100;
// Speed of run: Step every n milliseconds. Default 100.
AB.maxSteps = 1000;
// Length of run: Maximum length of run in steps. Default 1000.
AB.screenshotStep = 50;
// Take screenshot on this step. (All resources should have finished loading.) Default 50.
//---- global constants: -------------------------------------------------------
const show3d = true,
// All Images
TEXTURE_WALL = "/uploads/starter/door.jpg",
TEXTURE_MAZE = "/uploads/starter/latin.jpg",
TEXTURE_AGENT = "/uploads/rajv261/Agent.jpeg",
TEXTURE_ENEMY = "/uploads/rajv261/Enemy11.jpeg",
TEXTURE_Arrow = "/uploads/rajv261/Enemy.jpeg",
//Music Tracks
MUSIC_BACK = "/uploads/rajv261/Rifle-Automatic-Fire-A-www.fesliyanstudios.com.mp3",
SOUND_ALARM = "/uploads/rajv261/Big-Grenade-Explosion-www.fesliyanstudios.com.mp3",
gridsize = 20; // 20,
// number of squares along side of world
NOBOXES = Math.trunc(gridsize * gridsize / 10 ), // 10
// density of maze - number of internal boxes
// (bug) use trunc or can get a non-intege
squaresize = 100, // size of square in pixels
MAXPOS = gridsize * squaresize, // length of one side in pixels
SKYCOLOR = 14548957, // a number, not a string
startRadiusConst = 0.8 * MAXPOS, // distance from centre to start the camera at
maxRadiusConst = 10 * MAXPOS; // maximum distance from camera we will render things
// Changes in AB World
ABHandler.MAXCAMERAPOS = maxRadiusConst, ABHandler.GROUNDZERO = true;
const 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"
];
//Actions picked by Mind
ACTION_LEFT = 0,
ACTION_RIGHT = 1,
ACTION_UP = 2,
ACTION_DOWN = 3,
ACTION_STAYSTILL = 4,
// contents of a grid square
GRID_BLANK = 0,
GRID_WALL = 1,
GRID_MAZE = 2;
var BOXHEIGHT;
var theagent, theenemy, shape, thecube, thestar;
var wall_texture, agent_texture, enemy_texture, maze_texture, arrow_texture;
var ei, ej, ai, aj;
var badsteps;
var goodsteps;
var start, end;
GRID = new Array(gridsize),
xi = [],
xj = [],
starArray = [],
openSet = [],
closedSet = [],
path = [];
function loadResources() // asynchronous file loads - call initScene() when all finished
{
var e = new THREE.TextureLoader, t = new THREE.TextureLoader, a = new THREE.TextureLoader, r = new THREE.TextureLoader, n = new THREE.TextureLoader;
e.load(TEXTURE_WALL, function (e)
{
e.minFilter = THREE.LinearFilter, wall_texture = e, !!(wall_texture && agent_texture && enemy_texture && maze_texture && arrow_texture) && initScene();
}),
t.load(TEXTURE_AGENT, function (e)
{
e.minFilter = THREE.LinearFilter, agent_texture = e, !!(wall_texture && agent_texture && enemy_texture && maze_texture && arrow_texture) && initScene();
}),
a.load(TEXTURE_ENEMY, function (e)
{
e.minFilter = THREE.LinearFilter, enemy_texture = e, !!(wall_texture && agent_texture && enemy_texture && maze_texture && arrow_texture) && initScene();
}),
r.load(TEXTURE_MAZE, function (e)
{
e.minFilter = THREE.LinearFilter, maze_texture = e, !!(wall_texture && agent_texture && enemy_texture && maze_texture && arrow_texture) && initScene();
}),
n.load(TEXTURE_Arrow, function (e)
{
e.minFilter = THREE.LinearFilter, arrow_texture = e, !!(wall_texture && agent_texture && enemy_texture && maze_texture && arrow_texture) && initScene();
});
}
function translate(e, t)
{
var a = new THREE.Vector3;
return a.y = 0, a.x = e * squaresize - MAXPOS / 2,
a.z = t * squaresize - MAXPOS / 2,
a;
}
function removeFromArray(e, t)
{
for (var a = e.length - 1;a >= 0; a--)
e[a] == t && e.splice(a, 1);
}
function Spot(e, t)
{
this.i = e,
this.j = t,
this.f = 0,
this.g = 0,
this.h = 0,
this.neighbors = [],
this.previous = void 0,0 === e || e === gridsize - 1 || 0 === t || t === gridsize - 1 ? (this.wall = true, shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize), (thecube = new THREE.Mesh(shape)).material = new THREE.MeshBasicMaterial({map: wall_texture}), thecube.position.copy(translate(e, t)), ABWorld.scene.add(thecube)) : this.wall = false;
for (var a = 0; a <= NOBOXES; a++)
e === xi[a] && t === xj[a] && (this.wall = true);
this.addNeighbors = function (e)
{
var t = this.i, a = this.j;
t < gridsize - 1 && this.neighbors.push(e[t + 1][a]), t > 0 && this.neighbors.push(e[t - 1][a]), a < gridsize - 1 && this.neighbors.push(e[t][a + 1]), a > 0 && this.neighbors.push(e[t][a - 1]);
};
}
// all file loads have returned
function initScene()
{
var e, t;
for (e = 0; e < gridsize; e++)
GRID[e] = new Array(gridsize);
for (var a = 0, r = 1; r <= NOBOXES; r++)
e = AB.randomIntAtoB(1, gridsize - 2), t = AB.randomIntAtoB(1, gridsize - 2), xi[a] = e, xj[a] = t, shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize), (thecube = new THREE.Mesh(shape)).material = new THREE.MeshBasicMaterial({map: maze_texture}), thecube.position.copy(translate(e, t)), ABWorld.scene.add(thecube), a++;
for (e = 0; e < gridsize; e++) for (t = 0; t < gridsize; t++)
GRID[e][t] = new Spot(e, t);
for (e = 0; e < gridsize; e++) for (t = 0; t < gridsize; t++)
GRID[e][t].addNeighbors(GRID);
do {
e = AB.randomIntAtoB(1, gridsize - 2), t = AB.randomIntAtoB(1, gridsize - 2);
} while (ei == e && ej == t || (ai == e && aj == t || !!GRID[e][t].wall));
ei = e,
ej = t,
shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize),
(theenemy = new THREE.Mesh(shape)).material = new THREE.MeshBasicMaterial({map: enemy_texture}),
ABWorld.scene.add(theenemy),
drawEnemy();
do {
e = AB.randomIntAtoB(1, gridsize - 2), t = AB.randomIntAtoB(1, gridsize - 2);
} while (ei == e && ej == t || (ai == e && aj == t || !!GRID[e][t].wall));
ai = e,
aj = t,
shape = new THREE.BoxGeometry(squaresize, BOXHEIGHT, squaresize),
(theagent = new THREE.Mesh(shape)).material = new THREE.MeshBasicMaterial({map: agent_texture}),
ABWorld.scene.add(theagent), drawAgent(),
ABWorld.scene.background = (new THREE.CubeTextureLoader).load(SKYBOX_ARRAY,
function ()
{
ABWorld.render(),
AB.removeLoading(),
AB.runReady = true;
});
}
// ----- Moving objects ----- //
function drawEnemy()
{
theenemy.position.copy(translate(ei, ej)),
ABWorld.lookat.copy(theenemy.position);
}
function drawAgent()
{
theagent.position.copy(translate(ai, aj)),
ABWorld.follow.copy(theagent.position);
}
// ----- Function to draw path ----- //
function drawPath()
{
for (var e = 0; e < path.length - 2; e++) if (path.length > 2)
{
var t = path[e];
shape = new THREE.BoxGeometry(squaresize, 0.1, squaresize),
(thestar = new THREE.Mesh(shape)).material = new THREE.MeshBasicMaterial({map: arrow_texture}),
starArray[e] = thestar.uuid,
thestar.position.copy(translate(t.i, t.j)),
ABWorld.scene.add(thestar);
}
}
// ----- A* for enemy ----- //
function AStar()
{
for (openSet = [], closedSet = [], path = [], start = GRID[ei][ej], end = GRID[ai][aj], openSet.push(start); openSet.length > 0;)
{
for (var e = 0, t = 0; t < openSet.length; t++) openSet[t].f < openSet[e].f && (e = t);
var a = openSet[e];
if (a === end)
{
console.log("success - found path");
break;
}
removeFromArray(openSet, a),
closedSet.push(a);
var r = a.neighbors;
for (t = 0; t < r.length; t++)
{
var n = r[t];
if (!closedSet.includes(n) && !n.wall)
{
var o = a.g + (Math.abs(n.i - a.i) + Math.abs(n.j - a.j)), i = false;
openSet.includes(n) ? o < n.g && (n.g = o, i = true) : (n.g = o, i = true, openSet.push(n)),
i && (n.h = Math.abs(n.i - end.i) + Math.abs(n.j - end.j),
n.f = n.g + n.h, n.previous = a);
}
}
var s = a;
for ((path = []).push(s); s.previous;) path.push(s.previous),s = s.previous;
}
for (t = 0; t < gridsize; t++) for (var u = 0; u < gridsize; u++) 0 !== GRID[t][u].f && (GRID[t][u].f = 0, GRID[t][u].g = 0, GRID[t][u].h = 0, GRID[t][u].previous = void 0);
}
function removePath()
{
console.log("removing");
for (var e = 0; e < starArray.length; e++)
{
var t = starArray[e];
const a = ABWorld.scene.getObjectByProperty("uuid", t);
ABWorld.scene.remove(a);
}
}
// ----- Actions ----- //
function moveLogicalEnemy()
{
AStar(), drawPath();
var e = path.length,
t = path[e - 2];
ei == t.i && ej == t.j || (ai == t.i && aj == t.j || !!GRID[t.i][t.j].wall) || (ei = t.i, ej = t.j);
}
function sleep(e)
{
return new Promise(t => setTimeout(t, e));
}
function moveLogicalAgent(e)
{
var t = ai, a = aj;
e == ACTION_LEFT ? t-- : e == ACTION_RIGHT ? t++ : e == ACTION_UP ? a++ : e == ACTION_DOWN && a--,ei == t && ej == a || (ai == t && aj == a || !!GRID[t][a].wall) || (ai = t, aj = a);
}
var OURKEYS = [37, 38, 39, 40];
function keyHandler ( event )
{
if ( ! AB.runReady ) return true; // not ready yet
// if not one of our special keys, send it to default key handling:
if ( ! ourKeys ( event ) ) return true;
// else handle key and prevent default handling:
if ( event.keyCode == 37 ) moveLogicalAgent ( ACTION_LEFT );
if ( event.keyCode == 38 ) moveLogicalAgent ( ACTION_DOWN );
if ( event.keyCode == 39 ) moveLogicalAgent ( ACTION_RIGHT );
if ( event.keyCode == 40 ) moveLogicalAgent ( ACTION_UP );
// when the World is embedded in an iframe in a page, we want arrow key events handled by World and not passed up to parent
event.stopPropagation(); event.preventDefault(); return false;
}
function updateStatusBefore(e)
{
AB.world.getState();
AB.msg(" Step: " + AB.step + " a = (" + e + ") ");
}
function updateStatusAfter()
{
AB.world.getState();
var e = goodsteps / AB.step * 100;
AB.msg(" Bad steps: " + badsteps + " Good steps: " + goodsteps + " Score: " + e.toFixed(2) + "% ", 2);
}
AB.world.newRun = function ()
{
AB.loadingScreen(),
AB.runReady = false,
badsteps = 0,
goodsteps = 0,
BOXHEIGHT = squaresize,
ABWorld.init3d(startRadiusConst,
maxRadiusConst, 14548957),
loadResources(),
document.onkeydown = keyHandler;
}, AB.world.getState = function ()
{
return [ai, aj, ei, ej, GRID];
}, AB.world.takeAction = function (e)
{
updateStatusBefore(e),
moveLogicalAgent(e),
AB.step % 2 == 0 && moveLogicalEnemy(),
Math.abs(ei - ai) < 2 && Math.abs(ej - aj) < 2 ? badsteps++ : goodsteps++,
drawAgent(),
drawEnemy(),
updateStatusAfter(),
(ei == ai - 1 && ej == aj || (ai == ai - 1 && aj == aj || !!GRID[ai - 1][aj].wall)) && (ei == ai + 1 && ej == aj || (ai == ai + 1 && aj == aj || !!GRID[ai + 1][aj].wall)) && (ei == ai && ej == aj + 1 || (ai == ai && aj == aj + 1 || !!GRID[ai][aj + 1].wall)) && (ei == ai && ej == aj - 1 || (ai == ai && aj == aj - 1 || !!GRID[ai][aj - 1].wall)) && (AB.abortRun = true,
goodsteps = 0,
musicPause(),
soundAlarm()),
sleep(100).then(() => {
removePath();
});
}, AB.world.endRun = function ()
{
musicPause(),
AB.abortRun ? AB.msg(" <br> <font color=red> <B> Laden trapped. Final score zero. </B> </font> ", 3) : AB.msg(" <br> <font color=green> <B> Run over. </B> </font> ", 3);
}, AB.world.getScore = function ()
{
var e = goodsteps / AB.maxSteps * 100;
return Math.round(100 * e) / 100;
};
// ----- music and sound effects -----//
var backmusic = AB.backgroundMusic(MUSIC_BACK);
function musicPlay()
{
backmusic.play();
}
function musicPause()
{
backmusic.pause();
}
function soundAlarm()
{
new Audio(SOUND_ALARM).play();
}