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

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

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

下面我们上代码分析代码

1. 定义数组

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

  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]]
  2. 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]];
  3. boxArr = [[3, 3], [2, 4], [3, 4]];
  4. targetArr = [[2, 2], [1, 3], [2, 3]];

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

  1. initBox() {
  2. var textureBox = new THREE.TextureLoader().load("/static/images/base/crate.png");
  3. if (boxGroup) {
  4. scene.remove(boxGroup)
  5. }
  6. boxGroup = new THREE.Group();
  7. boxGroup.name = 'box_group'
  8. boxArr.forEach(d => {
  9. var boxGeom = new THREE.BoxGeometry(40, 40, 40);
  10. var boxMate = [];
  11. boxGeom.faces.forEach(d => boxMate.push(new THREE.MeshBasicMaterial({ map: textureBox })))
  12. var boxMesh = new THREE.Mesh(boxGeom, boxMate);
  13. boxMesh.position.set(d[0] * 40 - 20, 20, d[1] * 40 - 20);
  14. boxMesh.name = 'box';
  15. boxGroup.add(boxMesh);
  16. })
  17. scene.add(boxGroup);
  18. //判断是否赢得比赛
  19. this.isWinner(boxArr, targetArr)
  20. }

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

  1. initGround() {
  2. var textureGround = new THREE.TextureLoader().load("/static/images/wall/plaster.jpg", () => {this.loaded_num --});
  3. var textureGroundNormal = new THREE.TextureLoader().load("/static/images/wall/plaster-normal.jpg", () => {this.loaded_num --});
  4. var textureGroundSpecular = new THREE.TextureLoader().load("/static/images/wall/plaster-diffuse.jpg", () => {this.loaded_num --});
  5. textureGround.wrapS = textureGround.wrapT = THREE.RepeatWrapping;
  6. textureGround.repeat.set(50, 50);
  7. textureGroundNormal.wrapS = textureGroundNormal.wrapT = THREE.RepeatWrapping;
  8. textureGroundNormal.repeat.set(50, 50);
  9. var materialGround = new THREE.MeshPhongMaterial({
  10. map: textureGround
  11. })
  12. materialGround.normalMap = textureGroundNormal;
  13. materialGround.specularMap = textureGroundSpecular;
  14. var ground = new THREE.Mesh(new THREE.PlaneGeometry(1000, 1000, 1, 1), materialGround);
  15. ground.rotation.x = - Math.PI / 2;
  16. scene.add(ground);
  17. }

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

  1. initWall() {
  2. var normal = new THREE.TextureLoader().load("/static/images/wall/stone.jpg", () => {this.loaded_num --});
  3. var bump = new THREE.TextureLoader().load("/static/images/wall/stone-bump.jpg", () => {this.loaded_num --});
  4. wallArr.forEach(d => {
  5. var wallBox = new THREE.BoxGeometry(40, 40, 40);
  6. var material = new THREE.MeshPhongMaterial({
  7. map: normal,
  8. bumpMap: bump,
  9. bumpScale: 1
  10. })
  11. var wall = new THREE.Mesh(wallBox, material);
  12. wall.position.x = d[0] * 40 - 20;
  13. wall.position.y = 20;
  14. wall.position.z = d[1] * 40 - 20;
  15. scene.add(wall);
  16. })
  17. }

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

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

6. 监听箱子的点击事件

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

  1. initEventListener() {
  2. raycaster = new THREE.Raycaster();
  3. document.addEventListener('mousemove', function (event) {
  4. event.preventDefault();
  5. mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  6. mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
  7. }, false)
  8. document.addEventListener('click', () => {
  9. if (scene.children && scene.getObjectByName('box')) {
  10. raycaster.setFromCamera(mouse, camera);
  11. let intersects = raycaster.intersectObjects(scene.getObjectByName('box_group').children);
  12. if (intersects[0] && intersects[0].object.name == 'box') {
  13. this.computeMove(intersects[0].object, camera.position);
  14. }
  15. }
  16. })
  17. }

7. 监听游戏成功

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

  1. isWinner(arr1, arr2) {
  2. let boo = true; //true为赢
  3. arr1.forEach(d => {
  4. let res = arr2.some(dd => {
  5. return d[0] == dd[0] && d[1] == dd[1]
  6. })
  7. if(!res) {
  8. boo = false;
  9. }
  10. })
  11. if(boo) {
  12. setTimeout(() => {
  13. alert('恭喜你赢了!')
  14. },100)
  15. }
  16. }

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

转载请注明地址:郭先生的博客

three.js 制作一个三维的推箱子游戏的更多相关文章

  1. 用C写一个简单的推箱子游戏(二)

    下面接着上一篇随笔<用C写一个简单的推箱子游戏(一)>来写 tuidong()函数是用来判断游戏人物前方情况的函数,是推箱子游戏中非常重要的一个函数,下面从它开始继续介绍推箱子的小程序怎么 ...

  2. 用C写一个简单的推箱子游戏(一)

    我现在在读大二,我们有一门课程叫<操作系统>,课程考查要求我们可以写一段程序或者写Windows.iOS.Mac的发展历程.后面我结合网上的资料参考,就想用自己之前简单学过的C写一关的推箱 ...

  3. JavaScript写一个小乌龟推箱子游戏

    推箱子游戏是老游戏了, 网上有各种各样的版本, 说下推箱子游戏的简单实现,以及我找到的一些参考视频和实例: 推箱子游戏的在线DEMO : 打开 如下是效果图: 这个拖箱子游戏做了移动端的适配, 我使用 ...

  4. 用HTML5+原生js实现的推箱子游戏

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. 用JS制作一个信息管理平台完整版

      前  言 JRedu 在之前的文章中,介绍了如何用JS制作一个实用的信息管理平台. 但是那样的平台功能过于简陋了,我们今天来继续完善一下. 首先我们回顾一下之前的内容.   1.JSON的基础知识 ...

  6. JavaScript 推箱子游戏

    推箱子游戏的 逻辑非常简单,但是如果不动手的话,还是不太清楚.我在这里讲一下自己的思路. 制作推箱子,首先要有自己的设计素材.如下我也是网上找的素材 第二步,理清游戏的规则. 游戏规则: 1.小人将箱 ...

  7. 如何制作一个类似Tiny Wings的游戏(2) Cocos2d-x 2.1.4

    在第二篇<如何制作一个类似Tiny Wings的游戏>基础上,增加添加主角,并且使用Box2D来模拟主角移动,原文<How To Create A Game Like Tiny Wi ...

  8. C语言实现推箱子游戏完整代码

    C语言实现推箱子游戏完整代码 前言 自己做的,可能有些代码不够工整,或者有些小问题,但游戏的基本操作是可以实现的 代码效果 代码一共分为8个部分,4个控制上下左右移动,2个判断输赢,1个统计归为的个数 ...

  9. 怎样制作一个相似Tiny Wings的游戏 Cocos2d-x 2.1.4

    在第一篇<怎样使用CCRenderTexture创建动态纹理>基础上,添加�创建动态山丘,原文<How To Create A Game Like Tiny Wings with C ...

随机推荐

  1. PKIX

    这是证书认证不通过的问题,对https协议免认证 http://blog.csdn.net/zziamalei/article/details/46520797 使用上面的方法时,使用spring的& ...

  2. Python3笔记016 - 4.1 序列

    第4章 序列的应用 python的数据类型分为:空类型.布尔类型.数字类型.字节类型.字符串类型.元组类型.列表类型.字典类型.集合类型 在python中序列是一块用于存放多个值的连续内存空间. py ...

  3. API测试之Postman使用全指南(原来使用 Postman测试API如此简单)

    Postman Postman是一个可扩展的API开发和测试协同平台工具,可以快速集成到CI/CD管道中.旨在简化测试和开发中的API工作流. Postman 工具有 Chrome 扩展和独立客户端, ...

  4. Kafka消费者拉取数据异常Unexpected error code 2 while fetching data

    Kafka消费程序间歇性报同一个错: 上网没查到相关资料,只好自己分析.通过进一步分析日志发现,只有在拉取某一个特定的topic的数据时报错,如果拉取其他topic的数据则不会报错.而从这个异常信息来 ...

  5. Kail安装VMtools

    0x00 前言 之前用吾爱的xp虚拟机,总是装不上vmtools,真是难受.每次跨机器粘贴复制都一件极其痛苦的事,而且虚拟机还不能直接浏览硬盘上的文件.虽说安全性保证了,但是这是真的痛苦.这两天开始用 ...

  6. Django---进阶15

    目录 文章详情页 文章点赞点踩 文章评论 文章详情页 # url设计 /username/article/1 # 先验证url是否会被其他url顶替 # 文章详情页和个人站点基本一致 所以用模版继承 ...

  7. electron设置window系统托盘

    electron设置托盘 // 设置系统托盘 const setAppTray = () => { // 托盘对象 var appTray = null // 系统托盘右键菜单 var tray ...

  8. JVM 专题十五:执行引擎

    1. 执行引擎概述 1.1 执行引擎 1.2 概述 执行引擎是Java虚拟机的核心组成部分之一. 虚拟机是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处 ...

  9. python数据处理(六)之数据清洗:标准化和脚本化

    1.数据归一化和标准化 a. 归一化:对数据集进行计算,使数据都位于一个特定的范围\ b.标准化: c.删除离群值 2.数据存储 a.保存到SQLite数据库中 b.导出到简单的文件中csv 3.找到 ...

  10. 05 drf源码剖析之认证

    05 drf源码剖析之认证 目录 05 drf源码剖析之认证 1. 认证简述 2. 认证的使用 3. 源码剖析 4. 总结 1. 认证简述 当我们通过Web浏览器与API进行交互时,我们可以登录,然后 ...