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

今天郭先生发现大家更喜欢看我发的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 制作推箱子游戏的资料请关注我们其它相关文章!

(0)

相关推荐

  • js实现双人五子棋小游戏

    本文实例为大家分享了js实现双人五子棋小游戏的具体代码,供大家参考,具体内容如下 这是自己自学js的时候,在网上找的js源码,由于是自学,花了数小时才把这个源码大致弄明白. 大致算法 自定义棋盘规格,直接在棋盘建新div就可以,长度宽度用计算就可以了.下棋,在div里再建class,这里要给每个class标一个site值,由site值写出该棋子竖直方向和横向的坐标,由坐标可以写出棋子胜利的条件.而棋子的黑白走是用标识符,偶的标识符则是白棋子的class.奇的标识符则是黑棋子的class. ps

  • 微信小游戏之使用three.js 绘制一个旋转的三角形

    three.js是一个可以使用javascript绘制3d图形的库,它对WebGL的api进行封装,使开发更加方便,就像jQuery对DOM的api进行封装一样.接下来就记录一下在小游戏中绘制一个 旋转的三角形的步骤: 一. 初始化项目 下载微信官方的开发者工具,然后新建项目 appid选择测试号即可,项目路径自行指定 用编辑器打开项目,得到如下目录: 然后除了game.js,game.json, project.config.json全部删除,并把game.js中的内容清空. game.js是

  • C++实现推箱子小游戏源码

    本文实例为大家分享了C++实现推箱子小游戏的具体代码,供大家参考,具体内容如下 功能尚为完善. // ConsoleApplication2.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include<windows.h> #define KEY_DOWN(vk_code) GetAsyncKeyState(vk_code) & 0x8000 ? 1 : 0 using

  • javascript实现贪吃蛇小游戏

    本文实例为大家分享了js实现贪吃蛇小游戏的具体代码,供大家参考,具体内容如下 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> </body> <script> // 贪吃蛇: // 键盘的方向键,控制蛇的方向,碰撞食物,实现增加长度的

  • Three.js 再探 - 写一个微信跳一跳极简版游戏

    那么这个游戏到底是简单到什么程度,差不多就是到下面这个程度吧 源码地址:  github.com/luosijie/th- 由于是第一次尝试写游戏, 也不知道套路对不对, 大家看着玩就好, 不要太认真, 不推荐在手机上预览, 坑还没有填好 下面是实现过程 游戏分析 首先分析一下一个这样的游戏需要什么元素 Three.js必备元素: 场景,灯光,摄像机 一块又一块的方块 会跳的那个 ,或者叫游戏者 以上 游戏过程 初始一个场景, 场景中有一个 会跳的那个 和 2个方块 鼠标按下储存 能量值 鼠标放

  • DEVC++实现推箱子小游戏

    推箱子小游戏(基于DEVC++),供大家参考,具体内容如下 #include<iostream> #include<stdio.h> #include<conio.h> #include <windows.h> using namespace std; void Game_Menu(HANDLE hout); void Game_description(HANDLE hout); void gotoxy(HANDLE hout, int x, int y);

  • C语言实现简单推箱子游戏

    使用C语言实现超简单的推箱子游戏,供大家参考,具体内容如下/p> 感谢您打开了这篇文章,下面我将讲述一下推箱子是如何实现的. 另外附赠适配该程序简单好用 专属推箱子地图编辑器 让您在16 * 16大地图的条件下也能轻松编辑地图. 链接:地图编辑器 本程序在没有检测到地图文件的情况下也能独自运行!代码中储存了推箱子游戏第一关的标准地图,让您在没有地图文件的情况下也能熟悉整个程序的流程! 当然,拥有地图文件会也会获得更好的游戏体验,请自行编辑. 废话不多说! 下面进入技术环节: C语言版 多功能推箱

  • C++实现推箱子游戏

    一.项目简介 用两天闲余时间回顾了推箱子这款经典的小游戏,目前设置了5关,只能实现基本的人物移动.判断胜利条件,其他功能还未实现(例:撤回到上一步,自由选择关卡等),也顺便复习了C++的相关知识. 二. 代码区 Class Map(地图类) Map.h: #pragma once #define N 10 #define M 10 //地图类 class Map { public: Map(); ~Map(); void Init(); void ReadMapFile(int map[M][N

  • js实现简单五子棋游戏

    本文实例为大家分享了js实现五子棋游戏的具体代码,供大家参考,具体内容如下 html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>五子棋</title> <link rel="stylesheet" href="css/style.css" /> </head> <b

  • 纯JS实现五子棋游戏

    本文实例为大家分享了JS实现五子棋游戏的具体代码,供大家参考,具体内容如下 基本实现方式是表格,当时想用黑白圆棋代替的,但是尺寸没调好,就先上黑白底色了 说一下实现思路,刚开始是想每次落子的时候都把整个棋盘上的子遍历一遍,然后判断四个方向(横,竖,左斜,右斜)上的点数是不是想加等于5,做到一半的时候感觉这种效率太低了,也没必要,,然后就在每次落子之后判断它四个方向相加是不是等于5(不算落子本身),这是各个方向的最终效果 横向: 竖向: 左斜: 右斜: 横向和竖向的图是我修改过后的,加了一个定时器

随机推荐