如何使用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 相关文章推荐
ECMAScript 基础知识
Jun 29 Javascript
js 字符串转化成数字的代码
Jun 29 Javascript
JAVASCRIPT车架号识别/验证函数代码 汽车车架号验证程序
Jan 08 Javascript
jquery图片放大镜功能的实例代码
Mar 26 Javascript
jquery css 设置table的奇偶行背景色示例
Jun 03 Javascript
推荐5 个常用的JavaScript调试技巧
Jan 08 Javascript
尝试动手制作javascript放大镜效果
Dec 25 Javascript
onmouseover事件和onmouseout事件全面理解
Aug 15 Javascript
JavaScript定义函数的三种实现方法
Sep 23 Javascript
Angular resolve基础用法详解
Oct 03 Javascript
微信小程序封装自定义弹窗的实现代码
May 08 Javascript
vue如何获取自定义元素属性参数值的方法
May 14 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
joomla内置的表单验证功能使用方法
2010/06/11 PHP
php shell超强免杀、减少体积工具实现代码
2012/10/16 PHP
php 5.6版本中编写一个PHP扩展的简单示例
2015/01/20 PHP
ThinkPHP3.2框架自定义配置和加载用法示例
2018/06/14 PHP
Laravel框架表单验证操作实例分析
2019/09/30 PHP
用ADODB.Stream转换
2007/01/22 Javascript
js 判断浏览器类型 去全角、半角空格 自动关闭当前窗口
2009/04/10 Javascript
js 蒙版进度条(结合图片)
2010/03/10 Javascript
DOM Scripting中的图片切换[兼容Firefox]
2010/06/12 Javascript
Javascript中的for in循环和hasOwnProperty结合使用
2013/06/05 Javascript
js判断IE浏览器版本过低示例代码
2013/11/22 Javascript
jQuery如何将选中的对象转化为原始的DOM对象
2014/06/09 Javascript
jQuery使用元素属性attr赋值详解
2015/02/27 Javascript
jquery图片滚动放大代码分享(1)
2015/08/25 Javascript
JS实现弹性菜单效果代码
2015/09/07 Javascript
深入解析JavaScript中的数字对象与字符串对象
2015/10/21 Javascript
基于JavaScript如何制作遮罩层对话框
2016/01/26 Javascript
体验jQuery和AngularJS的不同点及AngularJS的迷人之处
2016/02/02 Javascript
Vue.set()实现数据动态响应的方法
2018/02/07 Javascript
PHP实现基于Redis的MessageQueue队列封装操作示例
2019/02/02 Javascript
jQuery内容选择器与表单选择器实例分析
2019/06/28 jQuery
小程序分页实践之编写可复用分页组件
2019/07/18 Javascript
JS实现可视化音频效果的实例代码
2020/01/16 Javascript
解决vant框架做H5时踩过的坑(下拉刷新、上拉加载等)
2020/11/11 Javascript
Python中基本的日期时间处理的学习教程
2015/10/16 Python
python 把数据 json格式输出的实例代码
2016/10/31 Python
Python实现二维数组按照某行或列排序的方法【numpy lexsort】
2017/09/22 Python
如何用python整理附件
2018/05/13 Python
让Python脚本暂停执行的几种方法(小结)
2019/07/11 Python
python 实现让字典的value 成为列表
2019/12/16 Python
Python timer定时器两种常用方法解析
2020/01/20 Python
python实现录屏功能(亲测好用)
2020/03/02 Python
Python字符串对齐、删除字符串不需要的内容以及格式化打印字符
2021/01/23 Python
美体小铺瑞典官方网站:The Body Shop瑞典
2018/01/27 全球购物
学校招生宣传广告词
2014/03/19 职场文书
成人成长感言如何写?
2019/08/16 职场文书