您现在的位置是:网站首页> 编程资料编程资料
基于 HTML5 的 WebGL 3D 版俄罗斯方块的示例代码基于 HTML5 WebGL 实现的垃圾分类系统HTML5 WebGL 实现民航客机飞行监控系统基于 HTML5 WebGL 实现的医疗物流系统
2023-10-16
302人已围观
简介 这篇文章主要介绍了基于 HTML5 的 WebGL 3D 版俄罗斯方块的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
前言
摘要:2D 的俄罗斯方块已经被人玩烂了,突发奇想就做了个 3D 的游戏机,用来玩俄罗斯方块。。。实现的基本想法是先在 2D 上实现俄罗斯方块小游戏,然后使用 3D 建模功能创建一个 3D 街机模型,最后将 2D 小游戏贴到 3D 模型上。
(ps:最后拓展部分实现将视频与3D模型的结合)

http://www.hightopo.com/demo/tetris/
代码实现
首先,先完成 2D 小游戏
在查看官方文档的过程中,了解到 HT 的组件参数都是保存在 ht.DataModel() 对象中,将数据模型在视图中进行加载后呈现各种特效。
gameDM = new ht.DataModel(); //初始化数据模型 g2d = new ht.graph.GraphView(gameDM); //初始化2d视图 g2d.addToDOM(); //在页面上创建视图
开始游戏模型的创建
第一步,先让我们为游戏创建一个框体,为游戏限定范围。在文档中,我们可以知道 ht.Node 是 graphView 呈现节点图元的基础类,除了可以显示图片外,还能支持多种预定义的图形。所以我打算使用该类创建4个长方形,用它们来做游戏的范围限定。
var lineNode = new ht.Node(); lineNode.s({ "shape": "rect", //矩形 "shape.background": "#D8D8D8", //设置底色 "shape.border.width": 1, //边框宽度 1 "shape.border.color": "#979797" // 边框颜色 }); lineNode.setPosition(x, y); // 设置图元展示位置,左上角为0, 0 图元坐标指向它们的中心位置 lineNode.setSize(width, height); // 设置图元宽、高属性 gameDM.add(lineNode); // 将设置好后的图元信息加入数据模型中设置 x:552, y:111, width:704, height:22 后我们可以得到第一个图形:

边框的top已经有了,现在让我们再创建另外三条边来组成一个框体:
x:211, y:562, width:22, width:880 x:893, y:562, width:22, width:880 x:552, y:1013, width:704, width:22
得到效果如下:

边框基本完成,在浏览的过程中发现4个边框可以被拖拽。接下来对边框初始化的方法进行调整:
lineNode.s({ "shape": "rect", //矩形 "shape.background": "#D8D8D8", //设置底色 "shape.border.width": 1, //边框宽度 1 "shape.border.color": "#979797", // 边框颜色 "2d.editable" : false, // 是否可编辑 "2d.movable" : false, //是否可移动 "2d.selectable" : false //是否可选中 });生成方块,我的想法是生成多个正方形,将它们组合成我们需要的图形,通过坐标的计算来将它们摆放在相应的位置:

方块生成后,开始对图形进行旋转操作。这其中有两个方案,第一种是将图形的翻转后的图形坐标按顺序保存在数组中,每次改变形状时取数组中的前一组或后一组坐标来进行改变;第二种是使用 ht.Block() 对象将对应的图元组合成一个整体,在变形时只需按对应的方向选择 90° 即可。在这里,我选择了第二中方式,代码如下:
function createUnit(x, y) { var node = new ht.Node(); node.s({ "shape": "rect", "shape.background": "#D8D8D8", "shape.border.width": 1, "shape.border.color": "#979797" }); node.setPosition(x, y); node.setSize(44, 44); gameDM.add(node); return node; } var block = new ht.Block(); block.addChild(createUnit(552, 133)); block.addChild(createUnit(552, 89)); block.addChild(createUnit(508, 133)); block.addChild(createUnit(596, 133)); block.setAnchor(0.5, 0.75); //设置组合的中心位置, 旋转时将安装此点来进行 block.setPosition(552, 144);Block 设置中心点 Anchor 如下图:

在设置旋转时,只需使用 setRotation 函数对 block 进行旋转即可:
方块有了,现在就该让它动起来了。设置定时器,使方块每隔一段时间下降一定距离,并添加键盘的监听事件,以此实现 w:翻转、s:左移动、d:右移动、s:下移的操作,同时为了不使方块移动出边界,在每次位移时都将对坐标进行一次验证:
var offset = 44; var intervalTime = 1000; var topX = 552; var topY = 111; var leftSize = 211, rightSize = 882, bottomSize = 1002; var rotationNum = 0; window.addEventListener('keydown', function(e){ var index = 0; var maxY = null; if(e.keyCode == 87){ // up w rotationNum ++; block.setRotation(Math.PI*rotationNum/2); if (!checkRotation(block)) { rotationNum --; block.setRotation(Math.PI*rotationNum/2); } } else if (e.keyCode == 65) { // left a moveBlock('x', -offset, block); } else if (e.keyCode == 68) { // right d moveBlock('x', offset, block); } else if(e.keyCode == 83){ // down s moveBlock('y', offset, block); } }, false); setInterval(function(){ if(!moveBlock("y", offset, block)){ //无法进行位移,创建新的方块 rotationNum = 0; //方块翻转次数归0 block = createNode(blockType); //生成新的方块 blockType = parseInt(Math.random()*100%5); //下一次生成的方块图形 } }, intervalTime); //执行间隔 //移动方块,移动成功时返回:true,无法移动时返回:false function moveBlock(axis, offset, block){ // 移动方块 var ids = []; var yindexs = []; var indexArr = new Array(); for(var i = 0; i < block.size(); i ++){ var childNode = block.getChildAt(i); var childx = childNode.getPosition().x; var childy = childNode.getPosition().y; if (yindexs.indexOf(childy) == -1) { yindexs.push(childy); } if(axis === 'x'){ childx += offset; }else if (axis === 'y') { childy += offset; } // 验证方块的移动是否超出边界 if(childx < leftSize || childx > rightSize || childy > bottomSize){ return false; } var obj = new Object(); obj.x = childx; obj.y = childy; indexArr.push(obj); ids.push(childNode.getId()); } //判断图形位移过程中是否与其他方块触碰 for(var j = 0; j < yindexs.length; j ++){ var indexY = yindexs[j]; if (axis === 'y') { indexY += offset; } //getDatasInRect 方法能获取到一个范围中的所有图元信息 var nodeList = g2d.getDatasInRect({x:233, y:indexY, width:638, height:2}, true, false); if(nodeList.length > 0){ // 触碰 for(var i = 0; i < nodeList.length; i++){ var x = nodeList.get(i).getPosition().x; var y = nodeList.get(i).getPosition().y; var id = nodeList.get(i).getId(); if (ids.indexOf(id) > -1) { // 位移的图元 continue; } for (var k = 0; k < indexArr.length; k++) { var obj = indexArr[k]; if (obj.x === x && obj.y === y){ // 该停下了 return false; } } } } } var blockX = block.getX(); var blockY = block.getY(); if (axis === 'x') { blockX += offset; }else if (axis === 'y') { blockY += offset; } // 方块移动到新的坐标 block.setPosition(blockX, blockY); return true; } // 验证方块是否可以进行翻转 function checkRotation(block){ for(var i = 0; i < block.getChildren().length; i++){ var node = block.getChildAt(i); var childx = node.getPosition().x; var childy = node.getPosition().y; // 判断翻转后的图形是否会超出范围 if(childx < leftSize || childx > rightSize || childy > bottomSize){ return false; } } return true; }在完成方块的位移与变形之后,我们的小游戏就只差最后一步了:对填充满的方块进行消除。在开始的时候,我们就知道所有的信息都是保存在数据模型当中,所以我们要消除方块。只需要将它们从数据模型中删除即可,实现代码如下:
function deleteBlock(block){ // 消除已经填充满的方格 var yindexs = []; // 要判断的y轴坐标 var num = 0; for(var i = 0; i < block.size(); i ++){ var childNode = block.getChildAt(i); var childy = childNode.getPosition().y; var nodeList = g2d.getDatasInRect({x:233, y:childy, width:638, height:2}, true, false); if (nodeList.length == 15) { for(var i = 0; i < nodeList.length; i++){ gameDM.remove(nodeList.get(i)); // 在数据模型中移除对应的图元 } num ++; yindexs.push(childy); } } if (yindexs.length > 0) { for(var i = 0 ; i < yindexs.length; i++){ // 将被消除图元上方的图元进行组合,并整体向下移动一个位置 var yindex = yindexs[i]; var h = yindex - 133 - offset; var moveList = g2d.getDatasInRect({x:233, y:133, width:638, height:h}, true, false); var mblock = new ht.Block(); for(var i = 0; i < moveList.size(); i++){ mblock.addChild(moveList.get(i)); } moveBlock('y', offset, mblock); } } }到此,一个简单的俄罗斯方块小游戏就实现了。当然,这个游戏还有很多可以拓展的地方,比如:更多的方块类型,游戏分数的统计,下一步预测窗体,游戏背景修改等。这些先不考虑,我们先开始下一步。
创建 3D 模型
在 3D 建模文档中了解到,HT 通过一个个三角形来组合模型。
首先,先将网络上查找到的街机模型进行拆分,将其中的各个模块拆分成三角形面:

如图所示,将0所在位置设置为原点(0,0,0),我们打开画图工具根据标尺大概估计出每个坐标相对原点的位置,将计算好的坐标数组传入 vs 中,同时在is顶点索引坐标中将每个三角图形的组合传入其中:
ht.Default.setShape3dModel('damBoard', { // 为新模型起名 vs: [ 0, 0, 0, //0 0.23, 0, 0, 0.23, 0.27, 0, 0.27, 0.28, 0, //3 0.27, 0.32, 0, 0.20, 0.33, 0, 0.18, 0.51, 0, // 6 0.27, 0.57, 0, 0.27, 0.655, 0, 0.20, 0.67, 0, // 9 0, 0.535, 0 ], is: [ 0, 1, 2, 0, 2, 5, 2, 3, 4, 4, 2, 5, 5, 0, 10, 10, 5, 6, 6, 7, 8, 8, 6, 9, 9, 10, 6 ] });与 2D 一样,我们创建一个 ht.Node() 的基础图元,类型设置为我们新注册的3D模型名称:
dataModel = new ht.DataModel(); g3d = new ht.graph3d.Graph3dView(dataModel); g3d.addToDOM(); var node = new ht.Node(); node.s({ 'shape3d': 'damBoard', 'shape3d.reverse.flip': true, '3d.movable': false, '3d.editable': false, '3d.selectable': false }); node.p3([0, 20, 0]); node.s3([100, 100, 100]); dataModel.add(node);
已经有个侧边了,我们可以将坐标系延z轴移动一定距离后得到另一个侧边的坐标数组同时再根据没个面的不同,分别设置 is 数组,将所有的面组合起来后,我们就将初步得到一个街机模型:
vs: [ 0, 0, 0, //0 0.23, 0, 0, 0.23, 0.27, 0, 0.27, 0.28, 0, //3 0.27, 0.32, 0, 0.20, 0.33, 0, 0.18, 0.51, 0, // 6 0.27, 0.57, 0, 0.27, 0.655, 0, 0.20, 0.67, 0, // 9 0, 0.535, 0, 0, 0, 0.4, //11 0.23, 0, 0.4, 0.23, 0.27, 0.4, 0.27, 0.28, 0.4, //14 0.27, 0.32, 0.4, 0.20, 0.33, 0.4, 0.18, 0.51, 0.4, // 17 0.27, 0.57, 0.4, 0.27, 0.655, 0.4,
相关内容
- html5-canvas中使用clip抠出一个区域的示例代码使用HTML5 Canvas API中的clip()方法裁剪区域图像
- HTML5 device access 设备访问详解html5实现点击弹出图片功能html5 录制mp3音频支持采样率和比特率设置html5表单的required属性使用html5调用摄像头实例代码HTML5页面音频自动播放的实现方式Html5大屏数据可视化开发的实现html实现弹窗的实例HTML5来实现本地文件读取和写入的实现方法HTML 罗盘式时钟的实现HTML5简单实现添加背景音乐的几种方法
- 详解canvas在圆弧周围绘制文本的两种写法HTML5 Canvas中使用用路径描画圆弧
- 全民飞机大战第一关通关攻略心得_全民飞机大战通关教程_手机游戏_游戏攻略_
- 全民飞机大战宠物资料介绍_全民飞机大战宠物有哪些_手机游戏_游戏攻略_
- 全民飞机大战天神祝福道具全面解析_全民飞机大战道具说明_手机游戏_游戏攻略_
- 全民飞机大战刷金币教程攻略_全民飞机大战刷金币心得_手机游戏_游戏攻略_
- 全民飞机大战刷分图文攻略_全民飞机大战刷分心得_手机游戏_游戏攻略_
- 全民英雄撼地小牛技能加点攻略详解_手机游戏_游戏攻略_
- 全民英雄游戏攻略 主坦克出装推荐_手机游戏_游戏攻略_
点击排行
本栏推荐
