如何使用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 相关文章推荐
jQuery 核心函数以及jQuery对象
Mar 23 Javascript
通过Jquery遍历Json的两种数据结构的实现代码
Jan 19 Javascript
文件编码导致jquery失效的解决方法
Jun 26 Javascript
JavaScript实现弹出子窗口并传值给父窗口
Dec 18 Javascript
jQuery中:checkbox选择器用法实例
Jan 03 Javascript
jquery获取checkbox的值并post提交
Jan 14 Javascript
精彩的Bootstrap案例分享 重点在注释!(选项卡、栅格布局)
Jul 01 Javascript
JS+canvas动态绘制饼图的方法示例
Sep 12 Javascript
Swiper自定义分页器使用详解
Dec 28 Javascript
vue监听用户输入和点击功能
Sep 27 Javascript
jQuery+ThinkPHP实现图片上传
Jul 23 jQuery
uni-app使用countdown插件实现倒计时
Nov 01 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 switch语句多个值匹配同一代码块的实现
2014/03/03 PHP
php导出中文内容excel文件类实例
2015/07/06 PHP
php ajax实现文件上传进度条
2016/03/29 PHP
PHP购物车类Cart.class.php定义与用法示例
2016/07/20 PHP
json 定义
2008/06/10 Javascript
跨浏览器的 mouseenter mouseleave 以及 compareDocumentPosition的使用说明
2010/05/04 Javascript
js 回车提交表单两种实现方法
2012/12/31 Javascript
JS实现表格数据各种搜索功能的方法
2015/03/03 Javascript
盘点javascript 正则表达式中 中括号的【坑】
2016/03/16 Javascript
使用jquery提交form表单并自定义action的实现代码
2016/05/25 Javascript
原生javascript实现分页效果
2017/04/21 Javascript
详解Vue2.0 事件派发与接收
2017/09/05 Javascript
js 公式编辑器 - 自定义匹配规则 - 带提示下拉框 - 动态获取光标像素坐标
2018/01/04 Javascript
JS实现简易贪吃蛇游戏
2020/08/24 Javascript
[01:08:29]DOTA2-DPC中国联赛定级赛 RNG vs Aster BO3第一场 1月9日
2021/03/11 DOTA
Python3指定路径寻找符合匹配模式文件
2015/05/22 Python
python生成器,可迭代对象,迭代器区别和联系
2018/02/04 Python
分析python动态规划的递归、非递归实现
2018/03/04 Python
python pandas dataframe 行列选择,切片操作方法
2018/04/10 Python
如何用Python来理一理红楼梦里的那些关系
2019/08/14 Python
pytorch 预训练层的使用方法
2019/08/20 Python
python实现画循环圆
2019/11/23 Python
Python object类中的特殊方法代码讲解
2020/03/06 Python
使用Python合成图片的实现代码(图片添加个性化文本,图片上叠加其他图片)
2020/04/30 Python
django数据模型中null和blank的区别说明
2020/09/02 Python
Python更改pip镜像源的方法示例
2020/12/01 Python
pytorch 实现L2和L1正则化regularization的操作
2021/03/03 Python
施华洛世奇中国官网:SWAROVSKI中国
2020/06/16 全球购物
网站开发实习生的自我评价
2013/12/11 职场文书
纪念建党演讲稿范文
2014/01/13 职场文书
进步之星获奖感言
2014/02/22 职场文书
环卫工作汇报材料
2014/10/28 职场文书
教师师德表现自我评价
2015/03/05 职场文书
2015年学校管理工作总结
2015/07/20 职场文书
2015秋季田径运动会广播稿
2015/08/19 职场文书
JavaScript使用canvas绘制坐标和线
2021/04/28 Javascript