本系列适合初学者,当然老鸟们能给一些指导就更好了,欢迎大家在底部评论留言。
迷宫指的是充满复杂通道,很难找到从其内部到达入口或从入口到达中心的道路,道路复杂难辨,人进去不容易出来的建筑物。
先来一张效果图。
先说下这个系列的一些设想,用户以第一视角的的方式通过迷宫,为了增加整个闯过的趣味性,准备加入一些冒险的玩法,比如答题提示、怪物攻击、不同形状的迷宫等。
迷宫利用深度优先+递归+回溯的方式生成。迷宫类包含生成和解法的方法。
代码注释已经很详细了,不在赘述。
只有一个出口,一个入口;解有且只有一个,行与列均为奇数;路径连续。
1 // 初始化迷宫数据 2 65 initData(maze) { 3 66 for (let i = 0; i < this.row; i++) { 4 67 maze[i] = new Array(this.col).fill(this.wall) // 初始化二维数组 5 68 this.visited[i] = new Array(this.col).fill(false) // 初始化访问状态为false 6 69 this.findPathVisited[i] = new Array(this.col).fill(false) // 初始化访问状态为false 7 70 8 71 for (let j = 0; j < this.col; j++) { 9 72 // 横纵坐标均为奇数 则是路 10 73 if (i % 2 === 1 && j % 2 === 1) { 11 74 maze[i][j] = this.road 12 75 } 13 76 } 14 77 } 15 78 // 入口及出口 则是路 16 79 maze[this.entryX][this.entryY] = this.road 17 80 maze[this.outX][this.outY] = this.road 18 81 19 82 return maze 20 83 }
调用迷宫类生成迷宫。这里为防止卡顿,生成13行13列的迷宫地图。
1 let mazeClass = new Maze(13,13, 10, 400, 400) 2 mazeClass.paintMaze(); 3 4 var geometry = new THREE.BoxGeometry(300, 200, 300); 5 var material = new THREE.MeshBasicMaterial({ 6 map: new THREE.TextureLoader().load("images/alien-carving.png") 7 }); 8 for (var i = 0; i < mazeClass.maze.length; i++) { 9 for (var j = 0; j < mazeClass.maze[i].length; j++) { 10 if (mazeClass.maze[i][j] === 1) { 11 var plane = new THREE.Mesh(geometry, material); 12 plane.position.set(300 * j, 0, 300 * i); 13 walls.push(plane); 14 scene.add(plane); 15 } 16 } 17 }
ThreeJS操作借鉴了FPS游戏的第一视角的方式进行探索,其中用到了天空盒、地面、物理等相关技术。
天空盒盒地面脚本:
1 // SKYBOX/FOG 2 var imagePrefix = "images/autumn-"; 3 var directions = ["xpos", "xneg", "ypos", "yneg", "zpos", "zneg"]; 4 var imageSuffix = ".png"; 5 var skyGeometry = new THREE.BoxGeometry(10000, 10000, 10000); 6 7 var materialArray = []; 8 for (var i = 0; i < 6; i++) 9 materialArray.push(new THREE.MeshBasicMaterial({ 10 map: new THREE.TextureLoader().load(imagePrefix + directions[i] + imageSuffix), 11 side: THREE.BackSide 12 })); 13 var skyBox = new THREE.Mesh(skyGeometry, materialArray); 14 scene.add(skyBox); 15 16 var floorT = new THREE.TextureLoader().load('images/rocky-ground.jpg'); 17 floorT.wrapS = floorT.wrapT = THREE.RepeatWrapping; 18 floorT.repeat.set(10, 10); 19 var floor = new THREE.Mesh(new THREE.BoxGeometry(50000, 50, 50000), 20 new THREE.MeshBasicMaterial({ 21 map: floorT 22 }) 23 ); 24 floor.position.set(0, -100, 0); 25 walls.push(floor); 26 scene.add(floor);
用户的第一视角脚本。第一视角用一个空的对象代替,用鼠标和键盘控制对象的移动。
1 person = new THREE.Object3D(); 2 person.add(camera); 3 camera.position.set(0, 35, 10); // first-person view 4 person.position.set(-600, 50, 500); 5 person.rotation.y = -Math.PI / 5.0; 6 7 boundingG = new THREE.BoxGeometry(40, 80, 40); 8 // radiusAtTop, radiusAtBottom, height, segmentsAroundRadius, segmentsAlongHeight, 9 // boundingG = new THREE.CylinderGeometry(20,20,80,8,2); 10 // better collision but FPS drops too much 11 12 boundingG.computeBoundingSphere(); 13 boundingM = new THREE.MeshBasicMaterial({ 14 color: 0xff0000, 15 transparent: true, 16 wireframe: true 17 }); 18 bounding = new THREE.Mesh(boundingG, boundingM); 19 bounding.visible = false; 20 person.add(bounding); 21 22 person.velocity = new THREE.Vector3(0, 0, 0); 23 24 scene.add(person);
体验地址:【http://www.yingbaiyou.cn/upload/maze/maze.html】
欢迎拍砖和不吝赐教,我这也是ThreeJS新手一枚。