如何使用three.js 制作一个三维的推箱子游戏


Posted in Javascript onJuly 29, 2020

今天郭先生发现大家更喜欢看我发的three.js小作品,今天我就发一个3d版本推箱子的游戏,其实webGL有很多框架,three.js并不合适做游戏引擎,但是可以尝试一些小游戏。在线案例请点击

要制作一个推箱子游戏,正常要有以下4个步骤

  1. 定义一些数组,要有开始箱子数组、结束箱子数组、地面数组还有墙面数组,有这四个数组就可以组成一个关卡。
  2. 根据数组初始化地面墙面箱子和目标地点标志物。
  3. 使用FirstPersonControls控制器,控制相机移动,根据地面箱子和墙面算出可移动区域。
  4. 根据相机正对箱子时,用鼠标点击箱子,控制箱子移动,并做成功性校验。

下面我们上代码分析代码

1. 定义数组

这四个数组分别是墙的数组、地面的数组、箱子初始位置数组和目标数组。

wallArr = [[0, 0], [1, 0], [2, 0], [3, 0], [3, 1], [4, 1], [4, 2], [4, 3], [5, 3], [5, 4], [5, 5], [5, 6], [4, 6], [3, 6], [2, 6], [1, 6], [0, 6], [0, 5], [0, 4], [0, 3], [0, 2], [0, 1]]
scopeArr = [[1, 1], [2, 1], [1, 2], [2, 2], [3, 2], [1, 3], [2, 3], [1, 4], [4, 4], [1, 5], [2, 5], [3, 5], [4, 5]];
boxArr = [[3, 3], [2, 4], [3, 4]];
targetArr = [[2, 2], [1, 3], [2, 3]];

2. 根据箱子初始位置数组初始化箱子

initBox() {
  var textureBox = new THREE.TextureLoader().load("/static/images/base/crate.png");
  if (boxGroup) {
    scene.remove(boxGroup)
  }
  boxGroup = new THREE.Group();
  boxGroup.name = 'box_group'
  boxArr.forEach(d => {
    var boxGeom = new THREE.BoxGeometry(40, 40, 40);
    var boxMate = [];
    boxGeom.faces.forEach(d => boxMate.push(new THREE.MeshBasicMaterial({ map: textureBox })))
    var boxMesh = new THREE.Mesh(boxGeom, boxMate);
    boxMesh.position.set(d[0] * 40 - 20, 20, d[1] * 40 - 20);
    boxMesh.name = 'box';
    boxGroup.add(boxMesh);
  })
  scene.add(boxGroup);
  //判断是否赢得比赛
  this.isWinner(boxArr, targetArr)
}

3. 根据地面数组初始化地面

initGround() {
  var textureGround = new THREE.TextureLoader().load("/static/images/wall/plaster.jpg", () => {this.loaded_num --});
  var textureGroundNormal = new THREE.TextureLoader().load("/static/images/wall/plaster-normal.jpg", () => {this.loaded_num --});
  var textureGroundSpecular = new THREE.TextureLoader().load("/static/images/wall/plaster-diffuse.jpg", () => {this.loaded_num --});
  textureGround.wrapS = textureGround.wrapT = THREE.RepeatWrapping;
  textureGround.repeat.set(50, 50);
  textureGroundNormal.wrapS = textureGroundNormal.wrapT = THREE.RepeatWrapping;
  textureGroundNormal.repeat.set(50, 50);
  var materialGround = new THREE.MeshPhongMaterial({
    map: textureGround
  })
  materialGround.normalMap = textureGroundNormal;
  materialGround.specularMap = textureGroundSpecular;
  var ground = new THREE.Mesh(new THREE.PlaneGeometry(1000, 1000, 1, 1), materialGround);
  ground.rotation.x = - Math.PI / 2;
  scene.add(ground);
}

4. 根据墙数组初始化地面

initWall() {
  var normal = new THREE.TextureLoader().load("/static/images/wall/stone.jpg", () => {this.loaded_num --});
  var bump = new THREE.TextureLoader().load("/static/images/wall/stone-bump.jpg", () => {this.loaded_num --});
  wallArr.forEach(d => {
    var wallBox = new THREE.BoxGeometry(40, 40, 40);
    var material = new THREE.MeshPhongMaterial({
      map: normal,
      bumpMap: bump,
      bumpScale: 1
    })
    var wall = new THREE.Mesh(wallBox, material);
    wall.position.x = d[0] * 40 - 20;
    wall.position.y = 20;
    wall.position.z = d[1] * 40 - 20;
    scene.add(wall);
  })
}

5. 根据目标数组初始化目标物

initTarget() {
  let objLoader = new OBJLoader();
  objLoader.setPath("/static/images/texture/hongqi/");
  objLoader.load('hongqi.obj', (object) => {
    this.loaded_num --;
    let hongqi = object.children[0];
    targetArr.forEach(d => {
      hongqi.position.set(d[0] * 40 - 20, -50, d[1] * 40 - 20)
      hongqi.scale.set(0.12, 0.12, 0.12)
      hongqi.material = new THREE.MeshNormalMaterial({ side: THREE.DoubleSide });
      scene.add(hongqi.clone())
    })
  })
}

6. 监听箱子的点击事件

每次点击的时候执行computeMove方法,判断如果是否可移动。

initEventListener() {
  raycaster = new THREE.Raycaster();
  document.addEventListener('mousemove', function (event) {
    event.preventDefault();
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
  }, false)
  document.addEventListener('click', () => {
    if (scene.children && scene.getObjectByName('box')) {
      raycaster.setFromCamera(mouse, camera);
      let intersects = raycaster.intersectObjects(scene.getObjectByName('box_group').children);
      if (intersects[0] && intersects[0].object.name == 'box') {
        this.computeMove(intersects[0].object, camera.position);
      }
    }
  })
}

7. 监听游戏成功

如果成功了,那么简单的弹出提示。

isWinner(arr1, arr2) {
  let boo = true; //true为赢
  arr1.forEach(d => {
    let res = arr2.some(dd => {
      return d[0] == dd[0] && d[1] == dd[1]
    })
    if(!res) {
      boo = false;
    }
  })
  if(boo) {
    setTimeout(() => {
      alert('恭喜你赢了!')
    },100)
  }
}

由于当时做这个小案例时还是菜鸟,所以很少用一些three.js的辅助方法,见笑了。

以上就是如何使用three.js 制作一个三维的推箱子游戏的详细内容,更多关于three.js 制作推箱子游戏的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JAVASCRIPT IE 与 FF中兼容问题小结
Feb 18 Javascript
JQuery页面图片切换和新闻列表滚动效果的具体实现
Sep 26 Javascript
JQuery实现倒计时按钮具体方法
Nov 14 Javascript
jquery live()调用不存在的解决方法
Feb 26 Javascript
用javascript将数据导入Excel示例代码
Sep 10 Javascript
JavaScript数组常用方法
Mar 02 Javascript
AngularJS 如何在控制台进行错误调试
Jun 07 Javascript
Bootstrap幻灯片轮播图支持触屏左右手势滑动的实现方法
Oct 13 Javascript
BootStrap按钮标签及基本样式
Nov 23 Javascript
Bootstrap常用组件学习(整理)
Mar 24 Javascript
angular4 JavaScript内存溢出问题
Mar 06 Javascript
JavaScript使用闭包模仿块级作用域操作示例
Jan 21 Javascript
Vue实现input宽度随文字长度自适应操作
Jul 29 #Javascript
vue 判断元素内容是否超过宽度的方式
Jul 29 #Javascript
在vue中实现给每个页面顶部设置title
Jul 29 #Javascript
vue实现移动端项目多行文本溢出省略
Jul 29 #Javascript
ElementUI 修改默认样式的几种办法(小结)
Jul 29 #Javascript
Element中Slider滑块的具体使用
Jul 29 #Javascript
vue 实现超长文本截取,悬浮框提示
Jul 29 #Javascript
You might like
关于svn冲突的解决方法
2013/06/21 PHP
网站防止被刷票的一些思路与方法
2015/01/08 PHP
php实现在服务器上创建目录的方法
2015/03/16 PHP
php官方微信接口大全(微信支付、微信红包、微信摇一摇、微信小店)
2015/12/21 PHP
CodeIgniter扩展核心类实例详解
2016/01/20 PHP
Smarty模板配置实例简析
2019/07/20 PHP
通过代码实例解析PHP session工作原理
2020/12/11 PHP
Javascript简单实现面向对象编程继承实例代码
2015/11/27 Javascript
深入理解jQuery 事件处理
2016/06/14 Javascript
AngularJS过滤器详解及示例代码
2016/08/16 Javascript
使用node.js中的Buffer类处理二进制数据的方法
2016/11/26 Javascript
关于js的三种使用方式(行内js、内部js、外部js)的程序代码
2018/05/05 Javascript
解决vue中post方式提交数据后台无法接收的问题
2018/08/11 Javascript
vue项目中使用lib-flexible解决移动端适配的问题解决
2018/08/23 Javascript
vue实现吸顶、锚点和滚动高亮按钮效果
2019/10/21 Javascript
Python中几个比较常见的名词解释
2015/07/04 Python
结合Python的SimpleHTTPServer源码来解析socket通信
2016/06/27 Python
TensorFlow实现模型评估
2018/09/07 Python
int在python中的含义以及用法
2019/06/27 Python
python实现控制COM口的示例
2019/07/03 Python
使用python切片实现二维数组复制示例
2019/11/26 Python
python字符串判断密码强弱
2020/03/18 Python
Python3.9新特性详解
2020/10/10 Python
使用Python下载抖音各大V视频的思路详解
2021/02/06 Python
Watchshop德国:欧洲在线手表No.1
2019/06/20 全球购物
幼儿园教师培训方案
2014/02/04 职场文书
如何写一封打动人心的求职信
2014/02/17 职场文书
《童年》教学反思
2014/02/18 职场文书
项目建议书模板
2014/05/12 职场文书
党员群众路线承诺书
2014/05/20 职场文书
建筑院校毕业生求职信
2014/06/13 职场文书
党员一帮一活动总结
2014/07/08 职场文书
法定代表人资格证明书
2014/09/11 职场文书
大一工商管理职业生涯规划:有梦最美,行动相随
2014/09/18 职场文书
辅导员学期工作总结
2015/08/14 职场文书
医务人员医德医风心得体会
2016/01/25 职场文书