three.js 制作一个三维的推箱子游戏
今天郭先生发现大家更喜欢看我发的three.js小作品,今天我就发一个3d版本推箱子的游戏,其实webGL有很多框架,three.js并不合适做游戏引擎,但是可以尝试一些小游戏。在线案例请点击博客原文。
要制作一个推箱子游戏,正常要有以下4个步骤
- 定义一些数组,要有开始箱子数组、结束箱子数组、地面数组还有墙面数组,有这四个数组就可以组成一个关卡。
- 根据数组初始化地面墙面箱子和目标地点标志物。
- 使用FirstPersonControls控制器,控制相机移动,根据地面箱子和墙面算出可移动区域。
- 根据相机正对箱子时,用鼠标点击箱子,控制箱子移动,并做成功性校验。
下面我们上代码分析代码
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 制作一个三维的推箱子游戏的更多相关文章
- 用C写一个简单的推箱子游戏(二)
下面接着上一篇随笔<用C写一个简单的推箱子游戏(一)>来写 tuidong()函数是用来判断游戏人物前方情况的函数,是推箱子游戏中非常重要的一个函数,下面从它开始继续介绍推箱子的小程序怎么 ...
- 用C写一个简单的推箱子游戏(一)
我现在在读大二,我们有一门课程叫<操作系统>,课程考查要求我们可以写一段程序或者写Windows.iOS.Mac的发展历程.后面我结合网上的资料参考,就想用自己之前简单学过的C写一关的推箱 ...
- JavaScript写一个小乌龟推箱子游戏
推箱子游戏是老游戏了, 网上有各种各样的版本, 说下推箱子游戏的简单实现,以及我找到的一些参考视频和实例: 推箱子游戏的在线DEMO : 打开 如下是效果图: 这个拖箱子游戏做了移动端的适配, 我使用 ...
- 用HTML5+原生js实现的推箱子游戏
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 用JS制作一个信息管理平台完整版
前 言 JRedu 在之前的文章中,介绍了如何用JS制作一个实用的信息管理平台. 但是那样的平台功能过于简陋了,我们今天来继续完善一下. 首先我们回顾一下之前的内容. 1.JSON的基础知识 ...
- JavaScript 推箱子游戏
推箱子游戏的 逻辑非常简单,但是如果不动手的话,还是不太清楚.我在这里讲一下自己的思路. 制作推箱子,首先要有自己的设计素材.如下我也是网上找的素材 第二步,理清游戏的规则. 游戏规则: 1.小人将箱 ...
- 如何制作一个类似Tiny Wings的游戏(2) Cocos2d-x 2.1.4
在第二篇<如何制作一个类似Tiny Wings的游戏>基础上,增加添加主角,并且使用Box2D来模拟主角移动,原文<How To Create A Game Like Tiny Wi ...
- C语言实现推箱子游戏完整代码
C语言实现推箱子游戏完整代码 前言 自己做的,可能有些代码不够工整,或者有些小问题,但游戏的基本操作是可以实现的 代码效果 代码一共分为8个部分,4个控制上下左右移动,2个判断输赢,1个统计归为的个数 ...
- 怎样制作一个相似Tiny Wings的游戏 Cocos2d-x 2.1.4
在第一篇<怎样使用CCRenderTexture创建动态纹理>基础上,添加�创建动态山丘,原文<How To Create A Game Like Tiny Wings with C ...
随机推荐
- My97DatePicker 4.8
https://jeesite.gitee.io/front/my97/demo/index.htm
- js写一个简单的九九乘法表
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 【转】Hbuilder配置Avalon、Vue指令提示
转载自CSDN http://blog.csdn.net/jianggujin/article/details/71419828 我本人是一名Java后端开发,偶尔也会研究一下前端内容,因为Hbuil ...
- MySQL数据库06 /数据库总结
MySQL数据库06 /数据库总结 目录 MySQL数据库06 /数据库总结 1. 数据库/DBMS 2. 数据库分类 3. 修改密码 4. 库操作 5. 表操作 6. 存储引擎 7. 事务 8. 约 ...
- 使用Typora写博客,图片即时上传,无需第三方图床-EasyBlogImageForTypora
背景 习惯使用markdown的人应该都知道Typora这个神器,它非常简洁高效.虽然博客园的在线markdown编辑器也不错,但毕竟是网页版,每次写东西需要登录系统-进后台-找到文章-编辑-保存草稿 ...
- Video 自动播放
先说ios ios之前的政策是视频只能在用户主动操作后才能播放,且播放时必须全屏. 随着 iOS 10 的正式发布,Safari 也迎来了大量更新,首先划出重点:1)iOS 10 Safari 支持特 ...
- 聊聊Mysql主从同步读写分离配置实现
Hi,各位热爱技术的小伙伴您们好,好久没有写点东西了,今天写点关于mysql主从同步配置的操作日志同大家一起分享.最近自己在全新搭建一个mysql主从同步读写分离数据库简单集群,我讲实际操作步骤整理分 ...
- mysql中常见约束
#常见约束 /* 含义:一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性 分类:六大约束 NOT NULL:非空,用于保证该字段的值不能为空 比如姓名.学号等 DEFAULT:默认,用于 ...
- mysql groupby 字段合并问题(group_concat)
在我们的日常mysql查询中,我们可能会遇到这样的情况: 对表中的所有记录进行分类,并且我需要得到每个分类中某个字段的全部成员. 上面的话,大家看起来可能不太好懂,下面举一个例子来给大家说明. 现在我 ...
- 定时器之Timer
Timer中的TimerTask就是一个线程,可以一直执行下去的.可以使用Timer类的cancel方法来结束.-------------------------------------------- ...