如何使用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 相关文章推荐
Confirmer JQuery确认对话框组件
Jun 09 Javascript
JS 模态对话框和非模态对话框操作技巧汇总
Apr 15 Javascript
让网页跳转到指定位置的jquery代码非书签
Sep 06 Javascript
IE8的JavaScript点击事件(onclick)不兼容的解决方法
Nov 22 Javascript
js根据日期判断星座的示例代码
Jan 23 Javascript
js判断手机端(Android手机还是iPhone手机)
Jul 22 Javascript
JavaScript实现删除,移动和复制文件的方法
Aug 05 Javascript
jQuery层级选择器实例代码
Feb 06 Javascript
jquery实现图片上传前本地预览
Apr 28 jQuery
vue 本地环境跨域请求proxyTable的方法
Sep 19 Javascript
vue项目配置使用flow类型检查的步骤
Mar 18 Javascript
Python版实现微信公众号扫码登陆
May 28 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
PHP性能优化工具篇Benchmark类调试执行时间
2011/12/06 PHP
PHP中让curl支持sock5的代码实例
2015/01/21 PHP
PHP+Ajax验证码验证用户登录
2016/07/20 PHP
PHP获取数组中指定的一列实例
2017/12/27 PHP
Firebug 字幕文件JSON地址获取代码
2009/10/28 Javascript
JS 自定义函数缺省值的设置方法
2010/05/05 Javascript
JavaScript 放大镜 放大倍率和视窗尺寸
2011/05/09 Javascript
JavaScript中的面向对象介绍
2012/06/30 Javascript
javascript alert乱码的解决方法
2013/11/05 Javascript
分享12个非常实用的JavaScript小技巧
2016/05/11 Javascript
总结jQuery插件开发中的一些要点
2016/05/16 Javascript
javaScript如何跳出多重循环break、continue
2016/09/01 Javascript
详解nodejs 文本操作模块-fs模块(四)
2016/12/22 NodeJs
从对象列表中获取一个对象的方法,依据关键字和值
2017/09/20 Javascript
深入理解Vue 的钩子函数
2018/09/05 Javascript
el-select 下拉框多选实现全选的实现
2019/08/02 Javascript
three.js利用卷积法如何实现物体描边效果
2019/11/27 Javascript
JS时间戳与日期格式互相转换的简单方法示例
2021/01/30 Javascript
解决vue-cli输入命令vue ui没效果的问题
2020/11/17 Javascript
javascript实现随机抽奖功能
2020/12/30 Javascript
python端口扫描系统实现方法
2014/11/19 Python
python实现读取并显示图片的两种方法
2017/01/13 Python
Python爬虫PyQuery库基本用法入门教程
2018/08/04 Python
详解python实现交叉验证法与留出法
2019/07/11 Python
Python操作excel的方法总结(xlrd、xlwt、openpyxl)
2019/09/02 Python
Keras中 ImageDataGenerator函数的参数用法
2020/07/03 Python
python 实现图片修复(可用于去水印)
2020/11/19 Python
解决tensorflow模型压缩的问题_踩坑无数,总算搞定
2021/03/02 Python
香港网上花店:FlowerAdvisor香港
2019/05/30 全球购物
会计助理的岗位职责
2013/11/29 职场文书
目标责任书范文
2014/04/14 职场文书
小学生三分钟演讲稿
2014/08/18 职场文书
人事专员岗位职责
2015/02/03 职场文书
市语委办2016年第十九届“推普周”活动总结
2016/04/05 职场文书
Nginx缓存设置案例详解
2021/09/15 Servers
Go语言读取txt文档的操作方法
2022/01/22 Golang