var Doors = function(game, maze, options) { var self=this; this.mesh = []; this.pivots = []; this.pivots_refs = {}; this.door_separators = []; this.outside_separators = []; var material; var depth; var depth2; var total_doors=0; this.cells = []; this.generated_doors = {}; this.data_doors = {}; this.load= function() { var self=this; depth = (Math.sqrt(3)/2) * game.opt.door_size*1.0; depth2 = (Math.sqrt(3)/2) * game.opt.door_size * Math.sqrt(3)/2 *1.35; var texloader = new THREE.TextureLoader(); this.cubeTexture=texloader.load('textures/wall.jpg'); this.cubeTexture.wireframe=true; this.cubeTexture.wrapS = this.cubeTexture.wrapT = THREE.RepeatWrapping; this.cubeTexture.repeat.set( 0.1, 0.1 ); return new Promise(function(ok, reject) { var ended=0; var loader = new THREE.JSONLoader(); loader.load( "js/meshes/door.js", function(geometry, mat) { self.door_geo = geometry; self.door_mat = mat; ended++; if(ended==2) { ok(); } }); loader.load( "js/meshes/wall.js", function(geometry, mat) { self.wall_geo = geometry; self.wall_mat = mat; ended++; if(ended==2) { ok(); } }); }); }; this.build = function() { var self=this; this.container = new THREE.Object3D(); this.floor_geom = new THREE.Geometry(); this.doors_geom = new THREE.Geometry(); this.num_items_line = Math.floor(Math.sqrt(options.maze_num)); var total=0; self.max_row = 0; self.max_line = 0; // Loop to create maze // Loop lines for(var row=0; (row0) { var opened_link = Math.floor(Math.random()*next_doors_unused.length); var dest_x = next_doors_unused[opened_link][0]; var dest_z = next_doors_unused[opened_link][1]; // Fill generated_doors data // Same row if(initial_x ==dest_x) { // Bottom door if(initial_z1) { // Visualize path var geometry = new THREE.BufferGeometry(); var positions = new Float32Array( 2 * 3 ); // 3 vertices per point geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); drawCount = 2; // draw the first 2 points, only geometry.setDrawRange( 0, drawCount ); var ref = this.cells[initial_x*this.num_items_line + initial_z]; var dest = this.cells[dest_x*this.num_items_line + dest_z]; var material = new THREE.LineBasicMaterial( { color: Math.random() * 0xffff00 + 0x0000ff, linewidth: 2 } ); line = new THREE.Line( geometry, material ); this.container.add( line ); var positions = line.geometry.attributes.position.array; positions[0]=(ref.position.x); positions[1]=(1); positions[2]=(ref.position.z); positions[3]=(dest.position.x); positions[4]=(1); positions[5]=(dest.position.z); } } // Do a maze with the not connected dots too else { for(var x=0; x<=this.max_row; x++) { for(var z=0; z<=this.max_line; z++) { // Need to link and unused cell with a used cell if(this.generated_doors[x][z] && !this.generated_doors[x][z].used) { next_doors_full = this.near_doors(x, z); next_doors_used=[]; next_doors_full.forEach(function(door) { if(self.generated_doors[door[0]][door[1]].used) { next_doors_used.push(door); } }); if(next_doors_used.length>0) { var connected_door = next_doors_used[Math.floor(Math.random()* next_doors_used.length)]; return this.maze_doors_next(connected_door); } } } } } }; this.near_doors = function(initial_x, initial_z) { var self=this; var next_doors = []; var pair = !!(initial_x%2===0); var check = []; // top check.push([ initial_x, initial_z-1]); // bottom check.push([ initial_x, initial_z+1]); // left top check.push([ initial_x-1, pair ? initial_z-1 : initial_z ]); // left bottom check.push([ initial_x-1, pair ? initial_z : initial_z+1]); // right top check.push([ initial_x+1, pair ? initial_z-1 : initial_z]); // right bottom check.push([ initial_x+1, pair ? initial_z : initial_z+1]); check.forEach(function(c) { var x = c[0]; var z = c[1]; if(self.generated_doors[x] && self.generated_doors[x][z]) { next_doors.push([x,z]); } }); return next_doors; }; /* Memorize the doors created, to avoid creating doble contiguous doors */ this.register_door= function(x, z, i, cell) { if(!this.data_doors[x+'.'+z]) { this.data_doors[x+'.'+z]={}; } this.data_doors[x+'.'+z][i] = 1; var pair= x%2==0; if(cell) { switch(i) { case 0: this.register_door(x, z+1, 3, false); break; case 1: this.register_door(x+1, pair? z : z+1, 4, false); break; case 2: this.register_door(x+1, pair ? z-1 : z, 5, false); break; } } }; this.get_pos = function(params) { var pair = params.x%2 ? depth2 : 0; var x =params.x * depth *2; var z =params.z * depth2 *2 + pair; return { x: x, z: z}; }; this.get_start_pos = function() { var coord = this.get_pos({ x: this.start_x , z: this.start_z }); return { x: coord.x + options.x , z: coord.z + options.z }; }; this.get_end_pos = function() { var coord = this.get_pos({ x: this.end_x - this.start_x , z: this.end_z - this.start_z }); return { x: coord.x + options.x , z: coord.z + options.z }; }; this.create_cell = function(params) { var self=this; this.fulldepth = game.opt.door_size + game.opt.door_size*2; var pair = params.x%2 ? depth2 : 0; var cell = new THREE.Object3D(); cell.name='pos '+params.x+' / '+params.z; var pos = this.get_pos(params); cell.position.x=pos.x; cell.position.y=0; cell.position.z=pos.z; this.cells.push(cell); this.container.add(cell); // Create ground of that pivot var geom = new THREE.Geometry(); var v1 = new THREE.Vector3(cell.position.x - game.opt.door_size/1.8 , 0 , cell.position.z-depth2*1.0 ); var v2 = new THREE.Vector3(cell.position.x - game.opt.door_size*1.2 , 0,cell.position.z); var v3 = new THREE.Vector3(cell.position.x - game.opt.door_size/1.8 , 0 , cell.position.z+depth2*1.0 ); var v4 = new THREE.Vector3(cell.position.x + game.opt.door_size/1.8 , 0 , cell.position.z+depth2*1.0 ); var v5 = new THREE.Vector3(cell.position.x + game.opt.door_size*1.2 , 0,cell.position.z); var v6 = new THREE.Vector3(cell.position.x + game.opt.door_size/1.8 , 0 , cell.position.z-depth2*1.0 ); var vcenter = new THREE.Vector3(cell.position.x ,1,cell.position.z); geom.vertices.push(vcenter); geom.vertices.push(v1); geom.vertices.push(v2); geom.vertices.push(v3); geom.vertices.push(v4); geom.vertices.push(v5); geom.vertices.push(v6); var material = new THREE.MeshBasicMaterial( { color: 0x3366bb } ); geom.faces.push( new THREE.Face3( 0, 1, 2 ) ); geom.faces.push( new THREE.Face3( 0, 2, 3 ) ); geom.faces.push( new THREE.Face3( 0, 3, 4 ) ); geom.faces.push( new THREE.Face3( 0, 4, 5 ) ); geom.faces.push( new THREE.Face3( 0, 5, 6 ) ); geom.faces.push( new THREE.Face3( 0, 6, 1) ); var object = new THREE.Mesh( geom, material); this.floor_geom.merge(object.geometry, object.matrix); //this.container.add(object); return cell; }; this.get_pivot = function(cell, params, i) { var pivot = new THREE.Object3D(); this.pivots.push(pivot); pivot.name ='p '+params.x+'/'+params.z+'/'+i; this.pivots_refs[params.x+'_'+params.z+'_'+i] = pivot; pivot.rotation.y= Math.radians(i*60); cell.add(pivot); return pivot; }; this.create_meshes = function(params) { var self=this; this.fulldepth = game.opt.door_size + game.opt.door_size*2; var cell = this.cells[params.num]; for(var i=0; i<6;i++) { if(!this.data_doors[params.x+'.'+params.z] || !this.data_doors[params.x+'.'+params.z][i]) { this.register_door(params.x, params.z, i, cell); total_doors++; var pivot = this.get_pivot(cell, params, i); var materials = []; var mesh; if(this.generated_doors[params.real_x][params.real_z].opened_doors.indexOf(i)!==-1) { //mesh = new THREE.Mesh( self.door_geo); //pivot.add(mesh); //this.mesh.push(mesh); } else { mesh = new THREE.Mesh( self.wall_geo); //pivot.add(mesh); //this.mesh.push(mesh); mesh.scale.x=game.opt.door_size; mesh.scale.y= game.opt.door_size; mesh.scale.z= game.opt.door_size; mesh.rotation.y= Math.radians(i*60); mesh.position.x = cell.position.x; mesh.position.y = cell.position.y; mesh.position.z = cell.position.z; switch(i) { case 0: mesh.position.z += game.opt.door_size; break; case 1: mesh.position.z += game.opt.door_size * 0.50; mesh.position.x += depth; break; case 2: mesh.position.z -= game.opt.door_size * 0.50; mesh.position.x += depth; break; case 3: mesh.position.z -= game.opt.door_size; break; case 4: mesh.position.z -= game.opt.door_size * 0.50; mesh.position.x -= depth; break; case 5: mesh.position.z += game.opt.door_size * 0.50; mesh.position.x -= depth; break; } mesh.updateMatrix(); //this.container.add(mesh); this.doors_geom.merge(mesh.geometry, mesh.matrix); //mesh.position.set(0, 0, game.opt.door_size); mesh.receiveShadow = true; } } var areas=[]; // Create collision items to detect enter in the cell if(this.generated_doors[params.real_x][params.real_z].opened_doors.indexOf(i)!==-1) { var door = this.generated_doors[params.real_x][params.real_z]; var outside_door = ( params.real_x == this.start_x && params.real_z == this.start_z && i == this.start_i) || ( params.real_x == this.end_x && params.real_z == this.end_z && i == this.end_i); this.create_separation_line(cell,params, i, false, outside_door); } } return cell; }; this.create_separation_line= function(cell,params, i, extra_door, outside_door) { var geometry = new THREE.BufferGeometry(); var positions = new Float32Array( 2 * 3 ); // 3 vertices per point geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); drawCount = 2; // draw the first 2 points, only geometry.setDrawRange( 0, drawCount ); var material = new THREE.LineBasicMaterial( { color: 0xffff00, linewidth: 2, transparent:true, opacity:0 } ); if(game.opt.debug_level>1) { material = new THREE.LineBasicMaterial( { color: Math.random() * 0xffff00 + 0x0000ff, linewidth: 2 } ); } var line = new THREE.Line( geometry, material ); var pivot = this.get_pivot(cell, params, i); pivot.add(line); var extra = extra_door ? game.opt.door_size*0.4 : 0; var positions = line.geometry.attributes.position.array; positions[0]=(depth*( !extra_door ? .5 : .7)); positions[1]=(1); positions[2]=(game.opt.door_size*0.9 +extra); positions[3]=(-depth*(!extra_door ? .5 : .7)); positions[4]=(1); positions[5]=(game.opt.door_size*0.9 +extra); line.name='l '+params.real_x+' / '+params.real_z; line.callback_data = {mazeid: maze.id, id:'cell_'+params.real_x+'_'+params.real_z, type:'change_cell', x: params.real_x, z:params.real_z}; line.mazeid = maze.id; self.door_separators.push(line); if(extra_door=='start'){ line.callback_data.action = 'leave_maze_from_start'; } if(extra_door=='end'){ line.callback_data.action = 'leave_maze_from_end'; } if(outside_door) { self.outside_separators.push(line); } }; }