Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- var orthoCamera, perspectiveCamera, scene, renderer, mesh, sphere, orthoControls, perspectiveControls;
- var scaleFactor;
- var doDraw;
- var direction;
- var lines = [[], [], [], [], [], [], [], []];
- var head;
- var done=true;
- var frameID;
- var fpsInterval;
- const ZOOM = 500;
- var unPauseTemp;
- const pause = function () {
- done = true;
- guiOptions.simulate.pauseUnpause = unPause;
- gui.__folders.Simulate.__controllers[0].name("Go")
- }
- unPauseTemp = function () {
- cancelAnimationFrame(frameID);
- done = false;
- guiOptions.simulate.pauseUnpause = pause;
- gui.__folders.Simulate.__controllers[0].name("Pause");
- startAnimating(guiOptions.simulate.fps, guiOptions.simulate.iterations)
- }
- const unPause = unPauseTemp;
- delete unPauseTemp;
- let guiOptions = {
- iteration: 0,
- dimensions: {
- width: 2,
- height:3,
- depth: 5
- },
- display: {
- orthoCamera:true,
- showOutline: true,
- outlineColor: 0xffb3,
- showHead: true,
- headColor: 0xff00,
- lineColor: 0xff0000
- },
- simulate: {
- pauseUnpause: unPause,
- reset: function () {
- //remove all lines from memory
- lines = [[], [], [], [], [], [], [], []];
- //remove all objects from scene
- while (scene.children.length > 0){scene.remove(scene.children[0])}
- //put everything we need back
- outline = new THREE.LineSegments(
- new THREE.EdgesGeometry(
- new THREE.BoxBufferGeometry(
- guiOptions.dimensions.width,
- guiOptions.dimensions.height,
- guiOptions.dimensions.depth
- )
- ),
- new THREE.LineBasicMaterial({color: guiOptions.display.outlineColor})
- );
- outline.visible=guiOptions.display.showOutline;
- outline.position.set(
- guiOptions.dimensions.width / 2,
- guiOptions.dimensions.height / 2,
- guiOptions.dimensions.depth / 2
- );
- scene.add(outline);
- orthoControls.target.set(
- guiOptions.dimensions.width / 2,
- guiOptions.dimensions.height / 2,
- guiOptions.dimensions.depth / 2
- );
- perspectiveControls.target.set(
- guiOptions.dimensions.width / 2,
- guiOptions.dimensions.height / 2,
- guiOptions.dimensions.depth / 2
- );
- sphere = new THREE.Mesh(
- new THREE.SphereGeometry(scaleFactor / 50, 16, 16),
- new THREE.MeshBasicMaterial({color: guiOptions.display.headColor})
- );
- sphere.visible=guiOptions.display.showHead;
- scene.add(sphere);
- arrowHelper = new THREE.ArrowHelper(
- new THREE.Vector3(1, 1, 1).normalize(),
- new THREE.Vector3(0, 0, 0), scaleFactor / 3,
- guiOptions.display.headColor
- );
- arrowHelper.visible=guiOptions.display.showHead;
- scene.add(arrowHelper);
- guiOptions.iteration = 0;
- gui.__controllers[0].name(0);
- head = [0, 0, 0];
- direction = 0;
- doDraw = true
- },
- fps: 60,
- iterations: 0
- }
- };
- //set
- gui = new dat.GUI();
- scaleFactor = (guiOptions.dimensions.width * guiOptions.dimensions.depth * guiOptions.dimensions.height) ** (1 / 3);
- gui.add(guiOptions, "iteration").name(0);
- gui.__controllers[0].domElement.hidden = true;
- document.getElementsByClassName("property-name")[0].style = "background-color:#2c2c2c;color:#2fa1d6";
- document.getElementsByClassName("cr number")[0].style = "background-color:#2c2c2c;padding-left:82.5px;font:400 13.3333px Arial;height:17px;text-align:center";
- let dimensions = gui.addFolder("Dimensions");
- dimensions.add(guiOptions.dimensions, "width", 1).name("Width").step(1).onChange(function () {
- guiOptions.dimensions.width = Math.max(.1, guiOptions.dimensions.width);
- onNewDimensions();
- }).onFinishChange(function () {
- orthoControls.target.x= guiOptions.dimensions.width/2;
- perspectiveControls.target.x=guiOptions.dimensions.width/2;
- });
- dimensions.add(guiOptions.dimensions, "height", 1).name("Height").step(1).onChange(function () {
- guiOptions.dimensions.height = Math.max(.1, guiOptions.dimensions.height);
- onNewDimensions();
- }).onFinishChange(function () {
- orthoControls.target.y= guiOptions.dimensions.height/2;
- perspectiveControls.target.y=guiOptions.dimensions.height/2;
- });
- dimensions.add(guiOptions.dimensions, "depth", 1).name("Depth").step(1).onChange(function () {
- guiOptions.dimensions.depth = Math.max(.1, guiOptions.dimensions.depth);
- onNewDimensions();
- }).onFinishChange(function () {
- orthoControls.target.z= guiOptions.dimensions.depth/2;
- perspectiveControls.target.z=guiOptions.dimensions.depth/2;
- });
- let display = gui.addFolder("Display");
- display.add(guiOptions.display,"orthoCamera").name("Orthographic Camera");
- display.add(guiOptions.display, "showOutline").name("Show box outline").onChange(function () {
- outline.visible = guiOptions.display.showOutline;
- });
- display.addColor(guiOptions.display, "outlineColor").name("Outline color").onChange(function () {
- outline.material.color = new THREE.Color(guiOptions.display.outlineColor);
- })
- display.add(guiOptions.display, "showHead").name("Show direction").onChange(function () {
- sphere.visible = guiOptions.display.showHead;
- arrowHelper.visible = guiOptions.display.showHead;
- });
- display.addColor(guiOptions.display, "headColor").name("Direction color").onChange(function () {
- sphere.material.color = new THREE.Color(guiOptions.display.headColor);
- arrowHelper.setColor(new THREE.Color(guiOptions.display.headColor));
- });
- display.addColor(guiOptions.display, "lineColor").name("Line color");
- display.open();
- let simulate = gui.addFolder("Simulate");
- simulate.add(guiOptions.simulate, "pauseUnpause").name("Go");
- simulate.add(guiOptions.simulate, "reset").name("Reset");
- simulate.add(guiOptions.simulate, "fps", Number.MIN_VALUE).step(.1).onChange(function () {
- fpsInterval = 1000 / guiOptions.simulate.fps;
- });
- simulate.add(guiOptions.simulate, "iterations", 0).step(1).name("Iterations");
- simulate.open();
- //init rendering stuff and objects
- scene = new THREE.Scene();
- var orthoCamera = new THREE.OrthographicCamera(
- -window.innerWidth / (ZOOM / scaleFactor),
- window.innerWidth / (ZOOM / scaleFactor),
- window.innerHeight / (ZOOM / scaleFactor),
- -window.innerHeight / (ZOOM / scaleFactor),
- -Number.MAX_VALUE, Number.MAX_VALUE
- );
- var perspectiveCamera = new THREE.PerspectiveCamera(
- 115,
- window.innerWidth / window.innerHeight,
- 0.0001, Number.MAX_SAFE_INTEGER
- );
- orthoCamera.position.set(
- -guiOptions.dimensions.width/2,
- guiOptions.dimensions.height*.75,
- -guiOptions.dimensions.depth/4
- );
- perspectiveCamera.position.set(
- -guiOptions.dimensions.width/2,
- guiOptions.dimensions.height*.75,
- -guiOptions.dimensions.depth/4
- );
- renderer = new THREE.WebGLRenderer();
- renderer.setSize(window.innerWidth, window.innerHeight);
- document.body.appendChild(renderer.domElement);
- orthoControls=new THREE.TrackballControls(orthoCamera,renderer.domElement);
- orthoControls.dynamicDampingFactor = .15;
- perspectiveControls=new THREE.TrackballControls(perspectiveCamera,renderer.domElement);
- perspectiveControls.dynamicDampingFactor = .15;
- guiOptions.simulate.reset();
- window.addEventListener('resize', function () {
- let width = window.innerWidth;
- let height = window.innerHeight;
- renderer.setSize(width, height);
- orthoCamera.left = -width / (ZOOM / scaleFactor);
- orthoCamera.right = width / (ZOOM / scaleFactor);
- orthoCamera.top = height / (ZOOM / scaleFactor);
- orthoCamera.bottom = -height / (ZOOM / scaleFactor);
- orthoCamera.updateProjectionMatrix();
- perspectiveCamera.aspect=width/height;
- perspectiveCamera.updateProjectionMatrix();
- orthoControls.update();
- perspectiveControls.update()
- })
- function onNewDimensions() {
- scaleFactor = (guiOptions.dimensions.width * guiOptions.dimensions.depth * guiOptions.dimensions.height) ** (1 / 3);
- scene.remove(outline, sphere, arrowHelper);
- sphere = new THREE.Mesh(
- new THREE.SphereGeometry(scaleFactor / 50, 16, 16),
- new THREE.MeshBasicMaterial({color: guiOptions.display.headColor})
- );
- scene.visible=guiOptions.display.showHead;
- scene.add(sphere);
- arrowHelper = new THREE.ArrowHelper(
- new THREE.Vector3(1, 1, 1).normalize(),
- new THREE.Vector3(0, 0, 0), scaleFactor / 3,
- guiOptions.display.headColor
- );
- arrowHelper.visible=guiOptions.display.showHead;
- scene.add(arrowHelper);
- outline = new THREE.LineSegments(
- new THREE.EdgesGeometry(
- new THREE.BoxBufferGeometry(
- guiOptions.dimensions.width,
- guiOptions.dimensions.height,
- guiOptions.dimensions.depth
- )
- ),
- new THREE.LineBasicMaterial({
- color: guiOptions.display.outlineColor
- })
- );
- outline.visible=guiOptions.display.showOutline;
- outline.position.set(
- guiOptions.dimensions.width / 2,
- guiOptions.dimensions.height / 2,
- guiOptions.dimensions.depth / 2
- );
- scene.add(outline);
- }
- //returns the end point and new direction of the head given its current position and direction
- function getEndPointAndDirection(head, direction) {
- const map = { 1: -1, 0: 1 };
- var t, tx, ty, tz;
- tx = direction & 0b100 ? head[0] : guiOptions.dimensions.width - head[0];
- ty = direction & 0b10 ? head[1] : guiOptions.dimensions.height - head[1];
- tz = direction & 1 ? head[2] : guiOptions.dimensions.depth - head[2];
- t = Math.min(tx, ty, tz);
- var newDirection = direction;
- newDirection = tx == t ? newDirection ^ 0b100 : newDirection;
- newDirection = ty == t ? newDirection ^ 0b10 : newDirection;
- newDirection = tz == t ? newDirection ^ 1 : newDirection;
- return [
- [
- head[0] + map[(direction & 0b100) >> 2] * t,
- head[1] + map[(direction & 0b10) >> 1] * t,
- head[2] + map[direction & 1] * t
- ],
- newDirection
- ];
- }
- function posTo0NegTo1(n) {
- return !(n > 0) & 1
- }
- //solve the equations b0+c0*t=b3+c3*u and b1+c1*t=b4*c4*u for t and u. returns t and u
- function solveEquations(b0, c0, b3, c3, b1, c1, b4, c4) {
- const map = { 1: -1, 0: 1 }
- var t;
- //if no division by 0
- if (map[c3] * map[c1] / map[c4] - map[c0]) {
- t = (b0 - b3 - map[c3] * ((b1 - b4) / map[c4])) / (map[c3] * map[c1] / map[c4] - map[c0]);
- return [
- t,
- (b1 - b4 + map[c1] * t) / map[c4]
- ]
- }
- }
- function getIntersectionAndT(head, direction, line) {
- const map = {1: -1, 0: 1};
- var t, u, myCalc, theirCalc;
- var dx = line[1][0] - line[0][0];
- var dy = line[1][1] - line[0][1];
- var dz = line[1][2] - line[0][2];
- var theirDirection = 4 * posTo0NegTo1(dx) + 2 * posTo0NegTo1(dy) + posTo0NegTo1(dz);
- var theirHead = line[0];
- var b0 = head[0];
- var c0 = direction >> 2;
- var b1 = head[1];
- var c1 = (direction & 0b10) >> 1;
- var b2 = head[2];
- var c2 = direction & 1;
- var b3 = theirHead[0];
- var c3 = theirDirection >> 2;
- var b4 = theirHead[1];
- var c4 = (theirDirection & 0b10) >> 1;
- var b5 = theirHead[2];
- var c5 = theirDirection & 1;
- //this part has way too much repetitive coede but I don't know what to do to fix it
- tAndU = solveEquations(b0, c0, b3, c3, b1, c1, b4, c4);
- if (tAndU) {
- [t, u] = tAndU;
- myCalc = [
- head[0] + map[direction >> 2] * t,
- head[1] + map[(direction >> 1) & 1] * t,
- head[2] + map[direction & 1] * t
- ];
- theirCalc = [
- theirHead[0] + map[theirDirection >> 2] * u,
- theirHead[1] + map[(theirDirection >> 1) & 1] * u,
- theirHead[2] + map[theirDirection & 1] * u
- ];
- if (t && myCalc[0] >= 0 && myCalc[0] <= guiOptions.dimensions.width && myCalc[1] >= 0 && myCalc[1] <= guiOptions.dimensions.height && myCalc[2] >= 0 && myCalc[2] <= guiOptions.dimensions.depth && myCalc[2] == theirCalc[2]) {
- return [
- [
- head[0] + map[direction >> 2] * t,
- head[1] + map[(direction & 0b10) >> 1] * t,
- head[2] + map[direction & 1] * t
- ],
- t
- ]
- }
- }
- tAndU = solveEquations(b0, c0, b3, c3, b2, c2, b5, c5);
- if (tAndU) {
- [t, u] = tAndU;
- myCalc = [head[0] + map[direction >> 2] * t, head[1] + map[(direction >> 1) & 1] * t, head[2] + map[direction & 1] * t];
- theirCalc = [theirHead[0] + map[theirDirection >> 2] * u, theirHead[1] + map[(theirDirection >> 1) & 1] * u, theirHead[2] + map[theirDirection & 1] * u];
- if (t && myCalc[0] >= 0 && myCalc[0] <= guiOptions.dimensions.width && myCalc[1] >= 0 && myCalc[1] <= guiOptions.dimensions.height && myCalc[2] >= 0 && myCalc[2] <= guiOptions.dimensions.depth && myCalc[1] == theirCalc[1]) {
- return [
- [
- head[0] + map[direction >> 2] * t,
- head[1] + map[(direction & 0b10) >> 1] * t,
- head[2] + map[direction & 1] * t
- ],
- t
- ]
- }
- }
- tAndU = solveEquations(b1, c1, b4, c4, b2, c2, b5, c5);
- if (tAndU) {
- [t, u] = tAndU;
- myCalc = [head[0] + map[direction >> 2] * t, head[1] + map[(direction >> 1) & 1] * t, head[2] + map[direction & 1] * t];
- theirCalc = [theirHead[0] + map[theirDirection >> 2] * u, theirHead[1] + map[(theirDirection >> 1) & 1] * u, theirHead[2] + map[theirDirection & 1] * u];
- if (t && myCalc[0] >= 0 && myCalc[0] <= guiOptions.dimensions.width && myCalc[1] >= 0 && myCalc[1] <= guiOptions.dimensions.height && myCalc[2] >= 0 && myCalc[2] <= guiOptions.dimensions.depth && myCalc[0] == theirCalc[0]) {
- return [
- [
- head[0] + map[direction >> 2] * t,
- head[1] + map[(direction & 0b10) >> 1] * t,
- head[2] + map[direction & 1] * t
- ],
- t
- ]
- }
- }
- }
- //does the simulation. Adds to the scene, updates relevant variables
- function main() {
- guiOptions.iteration++;
- gui.__controllers[0].name(guiOptions.iteration);
- const map = { 1: -1, 0: 1 };
- [endPoint, nextDirection] = getEndPointAndDirection(head, direction);
- //remove parralel lines from the list of lines to be tested against
- toTest = [0,1,2,3,4,5,6,7,8];
- toTest.splice(direction, 1);
- toTest.splice(toTest.indexOf(direction ^ 0b111), 1);
- //get all intersections
- var intersections = {};
- for (var theirDirection in toTest) {
- for (var line in lines[toTest[theirDirection]]) {
- var intersectionAndT = getIntersectionAndT(head, direction, lines[toTest[theirDirection]][line]);
- if (intersectionAndT) {
- var [intersection, t] = intersectionAndT
- }
- if (intersection && t > 0 && intersection[0] > 0 && intersection[0] < guiOptions.dimensions.width && intersection[1] > 0 && intersection[1] < guiOptions.dimensions.height && intersection[2] > 0 && intersection[2] < guiOptions.dimensions.depth) {
- intersections[t] = intersection;
- }
- }
- }
- intersections[0] = head;
- var lastIntersection = intersections[Object.keys(intersections)[Object.keys(intersections).length - 1]];
- //i'd like to do if (!(lastIntersection==endPoint)){...}, but for some reason that doesn't work
- if (!(lastIntersection[0] == endPoint[0] && lastIntersection[1] == endPoint[1] && lastIntersection[2] == endPoint[2])) {
- //get the greatest key, add one, and set that to the endpoint. This is done to insure the last itnersection is actually the last intersection
- intersections[Math.max(...Object.keys(intersections)) + 1] = endPoint;
- }
- intersections = Object.keys(intersections).reduce((a, b) => (a[b] = intersections[b], a), {});//black box. Sorts the intersections by t in ascending order
- //draw and store the lines
- var i = 0;
- if (!doDraw) {
- doDraw = true;
- i = 1;
- }
- for (i; i + 1 < Object.keys(intersections).length; i += 2) {
- lines[direction].push([
- intersections[Object.keys(intersections)[i]],
- intersections[Object.keys(intersections)[i + 1]]
- ]);
- geometry = new THREE.Geometry();
- geometry.vertices.push(
- new THREE.Vector3(...intersections[Object.keys(intersections)[i]])
- );
- geometry.vertices.push(
- new THREE.Vector3(...intersections[Object.keys(intersections)[i + 1]])
- );
- let line = new THREE.Line(
- geometry,
- new THREE.LineBasicMaterial({color: guiOptions.display.lineColor})
- );
- scene.add(line);
- }
- doDraw = (Object.keys(intersections).length - i) % 2 ? doDraw : !doDraw;
- head = endPoint;
- arrowHelper.position.set(...head);
- sphere.position.set(...head);
- direction = nextDirection;
- arrowHelper.setDirection(
- new THREE.Vector3(
- map[direction >> 2],
- map[(direction >> 1) & 1],
- map[direction & 1]
- ).normalize()
- );
- //if the head has reached a corner
- if ((head[0] == 0 || head[0] == guiOptions.dimensions.width) && (head[1] == 0 || head[1] == guiOptions.dimensions.height) && (head[2] == 0 || head[2] == guiOptions.dimensions.depth)) {
- return true;
- }
- }
- //animates howMany iterations of the game
- function animate(howMany) {
- //the stuff regarding time is used to render at a specific fps
- now = Date.now();
- elapsed = now - then;
- if (elapsed > fpsInterval) {
- then = now - (elapsed % fpsInterval);
- if (howMany && !done) {
- if (main()) {
- guiOptions.simulate.pauseUnpause()
- }
- howMany--
- }
- else if (!done){
- guiOptions.simulate.pauseUnpause()
- }
- }
- frameID = requestAnimationFrame(function(){animate(howMany)});
- orthoControls.update();
- perspectiveControls.update();
- if (guiOptions.display.orthoCamera){
- renderer.render(scene, orthoCamera)
- }
- else{
- renderer.render(scene, perspectiveCamera)
- }
- }
- //simplifies starting animations
- function startAnimating(fps, howMany) {
- fpsInterval = 1000 / fps;
- then = Date.now();
- if (!howMany) {
- howMany = Infinity;
- }
- animate(howMany);
- }
- startAnimating(guiOptions.simulate.fps);
Advertisement
Add Comment
Please, Sign In to add comment